-- act命令处理中心

local mis_uu = require('modules.commhm.utils')
local mis_bit = require('bit')
local mis_timer = require('modules.commhm.ngxTimerWrap')
local log       = require("modules.commhm.log");
local uu = mis_uu
local ngx = ngx
local pairs = pairs
local next = next
local math_floor = math.floor
local math_ceil = math.ceil
local math_max = math.max
local math_min = math.min
local math_random = math.random
local math_randomseed = math.randomseed
local math_huge = math.huge
local string_match = string.match
local string_format = string.format
local os_date = os.date
local os_time = os.time
local bor = mis_bit.bor
local band = mis_bit.band
local bnot = mis_bit.bnot
local lshift = mis_bit.lshift
local tonumber = tonumber
local tostring = tostring

local table_insert = table.insert
local table_remove = table.remove

local mis_config = nil
local mis_data = nil
local mis_log = nil
local mis_bridge = nil
local mis_common = nil
local mis_condition = nil
local mis_calcu = nil
local  mis_extend = nil
local mis_annualVote = nil
local mis_allowIp = nil
local mis_awakening = nil
local mis_boat_festival = nil
local t_retCode = nil
local mis_douluodalu = nil 
local mis_viptheme = nil
local mis_mapShare = nil
local mis_sanrio = nil
local mis_moon = nil
local mis_currency = nil

local n_WEEK_SEC = 7 * 86400 - 600	-- 6天23小时50分的秒数

-- 临时借用一下缓存
local t_cache = ngx.shared.misTime

--------------------------------------------------------------
local mis_act = {
	s_name = string.match(debug.getinfo(1).short_src, '.*/(.*).lua');	-- 模块名称
}
local this = mis_act

--------------------------------------------------------------
-- 说明：模块包含
-- 参数：模块表
this.modules_include = function(t_moddules)
	mis_config = t_moddules.mis_config
	mis_data = t_moddules.mis_data
	mis_log = t_moddules.mis_log
	mis_bridge = t_moddules.mis_bridge
	mis_common = t_moddules.mis_common
	mis_condition = t_moddules.mis_condition
	mis_calcu = t_moddules.mis_calcu
	mis_extend = t_moddules.mis_extend
	mis_annualVote = t_moddules.mis_annualVote
	mis_allowIp = t_moddules.mis_allowIp
	mis_awakening = t_moddules.mis_awakening
	t_retCode = mis_config.t_retCode
	mis_boat_festival = t_moddules.mis_boat_festival
	mis_douluodalu = t_moddules.mis_douluodalu
	mis_viptheme = t_moddules.mis_viptheme
	mis_mapShare = t_moddules.mis_mapShare
	mis_sanrio = t_moddules.mis_sanrio
	mis_moon = t_moddules.mis_moon
	mis_currency = t_moddules.mis_currency
	
	-- 觉醒活动
	this.awakening_upgrade_level   = mis_awakening.upgrade_level
	this.awakening_exchange_status = mis_awakening.exchange_status
	this.awakening_exchange        = mis_awakening.exchange
	this.awakening_rank_top        = mis_awakening.get_rank_top
	this.awakening_rank_update     = mis_awakening.update_rank
	this.awakening_get_mapaward    = mis_awakening.get_mapaward

	-- 端午节活动
	this.boat_festival_rank_top    = mis_boat_festival.get_rank_top
	this.boat_festival_rank_update     = mis_boat_festival.update_rank

	--斗罗大陆
	this.douluodalu_client_info = mis_douluodalu.douluodalu_client_info
	this.douluodalu_pick_rewards = mis_douluodalu.douluodalu_pick_rewards
	this.douluodalu_join_team = mis_douluodalu.douluodalu_join_team
	this.douluodalu_enter_map = mis_douluodalu.douluodalu_enter_map
	this.douluodalu_finish_map = mis_douluodalu.douluodalu_finish_map
	this.douluodalu_update_score = mis_douluodalu.douluodalu_update_score
	this.douluodalu_get_rank_top = mis_douluodalu.get_rank_top
	this.douluodalu_booking = mis_douluodalu.douluodalu_booking
	this.douluodalu_clear_data = mis_douluodalu.douluodalu_clear_data
	-- 会员主题
	this.batchbuy_vip_get_data     = mis_viptheme.batchbuy_vip_get_data
	this.vip_batchbuy_update_mem   = mis_viptheme.vip_batchbuy_update_mem
	this.vip_batchbuy_req          = mis_viptheme.vip_batchbuy_req
	this.vip_friendbuy_req         = mis_viptheme.vip_friendbuy_req
	this.pre_vip_theme             = mis_viptheme.pre_vip_theme
	this.task_prize_upgrade        = mis_viptheme.task_prize_upgrade
	this.task_prize_get_reward     = mis_viptheme.task_prize_get_reward
	this.clear_mission_data        = mis_viptheme.clear_mission_data

	-- 联机地图分享邀请
	this.request_map_share_code     = mis_mapShare.request_map_share_code
	this.exchange_map_share_code    = mis_mapShare.exchange_map_share_code
	this.verify_add_friend    		= mis_mapShare.verify_add_friend

	--三丽鸥
	--this.sanrio_pre_buy_skin = mis_sanrio.sanrio_pre_buy_skin
	--this.sanrio_buy_skin = mis_sanrio.sanrio_buy_skin
	--this.sanrio_reset_skin_info = mis_sanrio.sanrio_reset_skin_info
	--请求任务状态
	this.sanrio_task_status = mis_sanrio.sanrio_task_status
	this.sanrio_get_rewards = mis_sanrio.sanrio_get_rewards
	this.sanrio_buy_advace = mis_sanrio.sanrio_buy_advace
	this.sanrio_finish_task = mis_sanrio.sanrio_finish_task
	this.sanrio_reset_data = mis_sanrio.sanrio_reset_data
	this.sanrio_get_player_info = mis_sanrio.sanrio_get_player_info
	this.sanrio_secret_code = mis_sanrio.sanrio_secret_code
	this.sanrio_code_exchange = mis_sanrio.sanrio_code_exchange

	--三丽鸥中秋节活动
	this.reset_moon_data = mis_moon.reset_moon_data
	this.add_total_score = mis_moon.add_total_score
	this.moon_home_page = mis_moon.moon_home_page
	this.moon_light_up = mis_moon.moon_light_up
	this.moon_set_select_rewards = mis_moon.moon_set_select_rewards
	this.moon_get_select_rewards = mis_moon.moon_get_select_rewards
	this.moon_task_status = mis_moon.moon_task_status
	this.moon_get_task_rewards = mis_moon.moon_get_task_rewards
	this.moon_buy_cake = mis_moon.moon_buy_cake
	this.moon_finsh_task = mis_moon.moon_finsh_task
	this.moon_query_items = mis_moon.moon_query_items
	this.moon_query_ItemUseSkinDef = mis_moon.moon_query_ItemUseSkinDef
	
	this.moon_get_user_status = mis_moon.moon_get_user_status
	this.moon_get_user_mooncake_phone = mis_moon.moon_get_user_mooncake_phone
	this.moon_get_user_mooncake_vip_day = mis_moon.moon_get_user_mooncake_vip_day
	
	--2022国庆
	this.reset_national_data = mis_currency.reset_national_data
	this.national_home_page = mis_currency.national_home_page
	this.national_finsh_task = mis_currency.national_finsh_task
	this.national_get_task_rewards = mis_currency.national_get_task_rewards
	this.national_exchange_shop = mis_currency.national_exchange_shop
	this.national_exchange_items = mis_currency.national_exchange_items
	this.national_secret_code = mis_currency.national_secret_code
	this.national_code_exchange = mis_currency.national_code_exchange
	this.national_get_rank = mis_currency.national_get_rank
	this.national_set_rank = mis_currency.national_set_rank
	this.national_clear_rank = mis_currency.national_clear_rank

	--通用任务
	this.currency_home_page = mis_currency.currency_home_page
	this.currency_finsh_task = mis_currency.currency_finsh_task
	this.currency_get_task_rewards = mis_currency.currency_get_task_rewards
	this.currency_exchange_shop = mis_currency.currency_exchange_shop
	this.currency_exchange_items = mis_currency.currency_exchange_items
	this.currency_reset_data = mis_currency.currency_reset_data
	this.currency_add_score = mis_currency.currency_add_score
end

--------------------------------------------------------------
-- 说明：gift业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_gift = function()
	if mis_data.t_gift.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'gift disable'
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：获取礼包状态
-- 返回：n					状态码
--		ts 					描述
this.get_gift_status = function()
	local t_params = ngx.ctx.t_params
	local b_, b_userUpdate = nil, false
	local n_now, n_code = ngx.time()
	local t_2, t_3, t_user, t_userGift,t_userGift2, t_sysGift, ts_desc, t_userBiaoqian
	local t_giftStatus = mis_config.t_giftStatus
	local t_giftConf = mis_data.t_gift.t_conf
	local t_conditionConf = mis_data.t_gift.t_conditionConf

	-- 获取系统礼包数据
	n_code, t_sysGift = mis_data.get_user(0):get_gift_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_sysGift
	end

	-- 获取个人礼包数据(只存储限购礼包数据)
	t_user = mis_data.get_user()
	n_code, t_userGift, t_userGift2 = t_user:get_gift_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_userGift
	end

	-- 获取个人标签
	n_code, t_userBiaoqian = t_user:get_biaoqian()
	if n_code ~= t_retCode.n_OK then
		-- 如果没有拉到标签,这部分不检测
		t_userBiaoqian = {}
	end
	-- 集合客户端参数
	t_userBiaoqian.apiid = t_params.apiid
	t_userBiaoqian.ver = t_params.ver
	t_userBiaoqian.lang = t_params.lang
	t_userBiaoqian.country = t_params.country

	-- 个人数据治疗
	for n_giftId, t_ in pairs(t_userGift) do
		if(type(t_) == 'table') then
			t_2 = t_giftConf[n_giftId]
			t_3 = t_sysGift[n_giftId]
			-- 数据清理
			-- 如果配置删除礼包,或者礼包未上架或下架,删除数据
			if not t_2 or t_2.status == t_giftStatus.n_PRE or t_2.status == t_giftStatus.n_OFF then
				b_userUpdate = true
				t_userGift[n_giftId] = nil
			else
				-- 动态同步
				-- 配置突然删除展示条件
				-- 假设个人数据和配置数据是左右两个圆,中间有交集,后面代码会right join部分的数据
				-- 这里处理out left部分数据,将隐藏的礼包数据恢复展示
				if not t_conditionConf[n_giftId] and band(t_.status, t_giftStatus.n_HIDE) ~= 0 then
					b_userUpdate = true
					t_.status = band(t_.status, bnot(t_giftStatus.n_HIDE))
				end
				-- 配置突然改变限购属性
				if t_2.Limit then
					-- 限购
					if not t_.count then b_userUpdate = true; t_.count = 0 end
					-- 配置突然改变刷新属性/刷新个人礼包数据(限购解锁)
					if t_2.b_refresh then
						-- 刷新
						if t_.freshTime then
							if t_.freshTime < t_3.freshTime then
								b_userUpdate = true
								t_.status = band(t_.status, bnot(mis_config.t_giftStatus.n_SOLD_OUT))
								t_.count = 0
								t_.freshTime = t_3.freshTime
							end
						else
							b_userUpdate = true
							t_.freshTime = t_3.freshTime
						end
					else
						-- 不刷新
						if t_.freshTime then
							b_userUpdate = true
							t_.freshTime = nil
						end
					end
				else
					-- 不限购
					if t_.count then
						b_userUpdate = true
						t_.status = band(t_.status, bnot(mis_config.t_giftStatus.n_SOLD_OUT))
						t_.count = nil
						t_.freshTime = nil
					end
				end
				-- 冗余数据清理
				if t_.status == 0 and not t_.count then
					b_userUpdate = true
					t_userGift[n_giftId] = nil
				end
			end
		end
	end

	-- 根据条件刷新个人礼包数据
	for n_giftId, t_ in pairs(t_conditionConf) do
		-- 只检测上架的礼包
		if t_sysGift[n_giftId].status == t_giftStatus.n_ON then
			b_ = true
			t_2 = t_userGift[n_giftId]
			for _, t_3 in pairs(t_.t_condition) do
				-- 遍历查询礼包的限定条件,只要有一条不符合就隐藏礼包
				if not mis_condition[t_3.s_key](t_3.t_value, t_userBiaoqian) then
					b_ = false
					if not t_2 then
						b_userUpdate = true
						t_userGift[n_giftId] = {
							status = t_giftStatus.n_HIDE;
							count = t_giftConf[n_giftId].Limit and 0 or nil;
							freshTime = t_giftConf[n_giftId].Limit and t_giftConf[n_giftId].b_refresh and 0 or nil;
						}
						t_2 = t_userGift[n_giftId]
					elseif band(t_2.status, t_giftStatus.n_HIDE) == 0 then
						b_userUpdate = true
						t_2.status = bor(t_2.status, t_giftStatus.n_HIDE)
					end
					break
				end
			end
			-- 如果全条件符合，并且礼包是隐藏的，恢复展示
			if b_ and t_2 and band(t_2.status, t_giftStatus.n_HIDE) ~= 0 then
				b_userUpdate = true
				if t_2.status == t_giftStatus.n_HIDE then
					t_userGift[n_giftId] = nil
				else
					t_2.status = band(t_2.status, bnot(t_giftStatus.n_HIDE))
				end
			end
		end
	end

	-- set back
	if b_userUpdate then
		n_code, ts_desc = t_user:set_gift_data(t_userGift, t_userGift2)
		if n_code ~= t_retCode.n_OK then
			return n_code, ts_desc
		end
	end

	-- 计算客户端显示的刷新时间
	for n_giftId, t_ in pairs(t_userGift) do
		if(type(t_) == 'table') then
			if t_.freshTime then
				t_.interval = math.max(t_sysGift[n_giftId].nextTime - n_now, 0)
				t_.freshTime = nil
			end
		end
	end

	return n_code, t_userGift
end

--------------------------------------------------------------
-- 说明： 获取赠送信息
-- 参数：id 				 	 礼包id
-- 返回：n					 状态码
--		ts 					 赠送信息
this.present_gift_info = function()
	local t_params = ngx.ctx.t_params
	local n_code, t_userGift, t_userGift2, t_user
	local n_now = ngx.time()

	t_user = mis_data.get_user()
	n_code, t_userGift, t_userGift2 = t_user:get_gift_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_userGift
	end

	-- mis_log.debug("present_gift_info"..mis_common.table_to_json(t_userGift)..mis_common.table_to_json(t_userGift2))

	t_userGift2 = t_userGift2 or {}
	local b_anther_day = t_userGift2.lastPresentTime ~= nil
		and t_userGift2.lastPresentTime ~= 0
		and mis_common.is_another_day(t_userGift2.lastPresentTime, n_now) == true

	if b_anther_day then
		return t_retCode.n_OK, {lastPresentTime = 0}
	else
		if t_params.ver ~= t_userGift2.lastPresentTime then
			return t_retCode.n_OK, {lastPresentTime = t_userGift2.lastPresentTime, todayPresentedUser = t_userGift2.todayPresentedUser or {}}
		else
			return t_retCode.n_OK, {lastPresentTime = t_userGift2.lastPresentTime}
		end
	end

end

--------------------------------------------------------------
-- 说明：抽奖礼包赠送
-- 参数：id 				 礼包id
-- 返回：n					 状态码
--		ts 					 道具表
this.present_switch_gift = function()
	-- 礼包判定
	local t_params = ngx.ctx.t_params
	local n_code
	local n_giftId, n_price, n_now = t_params.id, 0, ngx.time()
	local s_presentStr = t_params.present_str
	local ts_desc, t_items, t_itemsMaidian, t_userGift, t_userGift2, t_user
	local t_giftConf = mis_data.t_gift.t_conf[n_giftId]
	local n_presentNum = t_params.num
	local n_costItemId

	-- 数目校验
	if n_presentNum <= 0 then
		ts_desc = 'num less than 0'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 是否好友
	n_code = mis_bridge.friend_has_relation(t_params.uin, t_params.presented_uin,3)
	if n_code ~= t_retCode.n_OK then
		ts_desc = 'friend error'..n_code
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 被赠送玩家判定
	n_code = mis_data.get_user(t_params.presented_uin):get_user_basic()
	if n_code ~= t_retCode.n_OK then
		ts_desc = 'user not found'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包存在性判定
	if not t_giftConf then
		ts_desc = 'conf not found'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 是否抽奖礼包
	if t_giftConf.switch_pack ~= 1 then
		ts_desc = 'not switch_pack'
		mis_log.error(ts_desc .. mis_common.table_to_string(t_giftConf))
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 能否赠送
	if t_giftConf.gift ~= 1 then
		ts_desc = 'can not present gift'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包时效性判定
	-- 系统礼包的状态刷新时间精度是分钟,所以不能用在这里
	if n_now < t_giftConf.BeginTime or n_now > t_giftConf.EndTime then
		return t_retCode.n_OPER_ERR, 'expired'
	end

	-- 礼包限购数据
	t_user = mis_data.get_user()
	n_code, t_userGift, t_userGift2 = t_user:get_gift_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_userGift
	end
	-- mis_log.debug("present_switch_gift"..mis_common.table_to_json(t_userGift)..mis_common.table_to_json(t_userGift2))

	-- 赠送,被赠送次数判定
	t_userGift2 = t_userGift2 or {}
	local b_anther_day = t_userGift2.lastPresentTime ~= nil
		and t_userGift2.lastPresentTime ~= 0
		and mis_common.is_another_day(t_userGift2.lastPresentTime, n_now) == true

	if b_anther_day == false then
		t_userGift2.todayPresentCount = t_userGift2.todayPresentCount or 0
		if t_userGift2.todayPresentCount >= t_giftConf.Presented then
			return t_retCode.n_OPER_ERR, 'present limit'
		end
		t_userGift2.todayPresentedUser = t_userGift2.todayPresentedUser or {}
		local n_presentedCount = t_userGift2.todayPresentedUser[t_params.presented_uin] or 0
		if n_presentedCount + t_params.num > t_giftConf.Be_presented then
			return t_retCode.n_OPER_ERR, 'presented limit'
		end
	end

	-- 计算消耗
	n_price = t_giftConf.Cost * n_presentNum

	-- 扣费
	if t_giftConf.CostType ~= mis_config.t_costType.n_FREE then
		n_price = math_max(0, math_ceil(n_price))
		n_code, ts_desc = mis_bridge.cost_money(t_params.uin, t_giftConf.ItemID, n_price, t_giftConf.CostType, 'present_switch_gift'
			,mis_common.table_to_json({aname = 'present_switch_gift',gift_id = n_giftId, gift_type = t_giftConf.GiftType}))
		if n_code ~= t_retCode.n_OK then
			mis_log.day('gift_error', 'present_switch_gift_sub_items|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
				(t_giftConf.ItemID or 'null') .. '|' .. n_price)
			return n_code, ts_desc
		end
	end

	-- 赠送附加
	if t_params.num >= t_giftConf.present_can_add then
		n_presentNum = n_presentNum + t_giftConf.present_add * math_floor(t_params.num / t_giftConf.present_can_add)
	end

	t_items = {{id = t_giftConf.Beitem, num = n_presentNum}}
	-- 赠送邮件
	n_code, ts_desc = mis_bridge.send_email(t_params.presented_uin, "收到礼物","收到"..t_params.uin.."的礼物:"..t_giftConf.title.."\\n祝福你:"..s_presentStr, 32503651200, t_items, 0)
	if n_code ~= t_retCode.n_OK then
		return n_code, ts_desc
	end

	-- 刷新赠送信息
	if b_anther_day == true then
		t_userGift2.todayPresentCount = t_userGift2.todayPresentCount or 0
		t_userGift2.todayPresentCount = t_userGift2.todayPresentCount + t_params.num
		t_userGift2.lastPresentTime = n_now
		t_userGift2.todayPresentedUser = {[t_params.presented_uin] = t_params.num}
	else
		t_userGift2.todayPresentCount = n_presentNum
		t_userGift2.lastPresentTime = n_now
		t_userGift2.todayPresentedUser = t_userGift2.todayPresentedUser or {}
		local n_presentedCount = t_userGift2.todayPresentedUser[t_params.presented_uin] or 0
		t_userGift2.todayPresentedUser[t_params.presented_uin] = n_presentedCount + t_params.num

	end

	t_user:set_gift_data(t_userGift, t_userGift2)

	-- 数据埋点
	t_items.giftId = n_giftId
	if t_giftConf.CostType == mis_config.t_costType.n_ITEM then n_costItemId =  t_giftConf.ItemID end
	t_itemsMaidian = {{id = t_giftConf.Beitem, num = n_presentNum, price = n_price}}
	mis_log.remote_day('gift', 'ok_present|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' .. t_params.country .. '|' ..
		t_params.lang .. '|' .. n_giftId .. '|' .. t_giftConf.title .. '|' .. mis_common.table_to_json(t_itemsMaidian) .. '|' ..
		(t_giftConf.RefreshType or 'nil') .. '|' .. t_giftConf.tag .. '|' .. t_giftConf.CostType .. '|' .. n_price .. '|' .. (n_costItemId or 'nil') .. '|' .. t_giftConf.GiftType .. '|' .. t_params.presented_uin)

	return t_retCode.n_OK, t_items
end

--------------------------------------------------------------
-- 说明：抽奖礼包购买
-- 参数：id 			     礼包id
-- 返回：n					 状态码
--		ts 					道具表
this.buy_switch_gift = function()
	local t_params = ngx.ctx.t_params
	local n_code
	local n_giftId, n_price, n_now = t_params.id, 0, ngx.time()
	local s_items
	local ts_desc, t_items, t_itemsMaidian, t_userGift, t_sysGift, t_user
	local t_giftConf = mis_data.t_gift.t_conf[n_giftId]
	local n_buyNum = t_params.num
	local n_costItemId
	local t_itemsSwitch

	-- 数目校验
	if n_buyNum <= 0 then
		ts_desc = 'num less than 0'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包存在性判定
	if not t_giftConf then
		ts_desc = 'conf not found'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 是否抽奖礼包
	if t_giftConf.switch_pack ~= 1 then
		ts_desc = 'not switch_pack'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包时效性判定
	-- 系统礼包的状态刷新时间精度是分钟,所以不能用在这里
	if n_now < t_giftConf.BeginTime or n_now > t_giftConf.EndTime then
		return t_retCode.n_OPER_ERR, 'expired'
	end

	-- 计算消耗
	n_price = t_giftConf.Cost * n_buyNum

    -- 扣费
	if t_giftConf.CostType ~= mis_config.t_costType.n_FREE then
		n_price = math_max(0, math_ceil(n_price))
		n_code, ts_desc = mis_bridge.cost_money(t_params.uin, t_giftConf.ItemID, n_price, t_giftConf.CostType, 'buy_switch_gift'
			,mis_common.table_to_json({aname = 'buy_switch_gift',gift_id = n_giftId, gift_type = t_giftConf.GiftType}))
		if n_code ~= t_retCode.n_OK then
			mis_log.day('gift_error', 'buy_switch_gift_sub_items|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
				(t_giftConf.ItemID or 'null') .. '|' .. n_price)
			return n_code, ts_desc
		end
	end

	-- 购买附加
	if t_params.num >= t_giftConf.buy_can_add then
		n_buyNum = n_buyNum + t_giftConf.buy_add * math_floor(t_params.num / t_giftConf.buy_can_add)
	end

	-- 放到仓库
	-- mis_log.debug(mis_common.table_to_string(t_params))
	t_items = {{id = t_giftConf.Beitem, num = n_buyNum}}
	n_code, ts_desc, s_items = mis_data.add_items(t_params.uin, t_items, mis_config.t_workType.s_GIFT, 'buy_switch_gift')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('gift_error', 'buy_switch_gift_add_items|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
		(t_giftConf.ItemID or 'null') .. '|' .. n_price .. '|' .. s_items)
		return n_code, ts_desc
	end

	t_items.giftId = n_giftId

	-- 本地记录
	t_itemsSwitch = mis_bridge.get_props_by_switch(t_giftConf.switch_id, t_giftConf.switch_id_num)

	t_itemsMaidian = {{id = t_giftConf.Beitem, num = n_buyNum, price = n_price}}
	if t_giftConf.CostType == mis_config.t_costType.n_ITEM then n_costItemId =  t_giftConf.ItemID end
	mis_log.remote_day('gift', 'ok_buy|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' .. t_params.country .. '|' ..
		t_params.lang .. '|' .. n_giftId .. '|' .. t_giftConf.title .. '|' .. mis_common.table_to_json(t_itemsMaidian) .. '|' ..
		(t_giftConf.RefreshType or 'nil') .. '|' .. t_giftConf.tag .. '|' .. t_giftConf.CostType .. '|' .. n_price .. '|' .. (n_costItemId or 'nil')
		.. '|' .. t_giftConf.GiftType .. '|' .. mis_common.table_to_json(t_itemsSwitch))

	-- [降级控制中]
	-- 通知福利服更新福利条件
	if mis_config.n_debug ~= 0 then
		n_code, ts_desc = mis_bridge.notify_ma_buy_gift(t_params.uin, n_giftId)
		if n_code ~= t_retCode.n_OK then
			mis_log.day('gift_error', 'buy_switch_gift_notify|' .. t_params.uin .. '|' .. n_giftId)
			return n_code, ts_desc
		end
	end

	return t_retCode.n_OK, t_items
end

--------------------------------------------------------------
-- 说明：抽奖礼包使用
-- 参数：id 			     礼包id
-- 返回：n					 状态码
--		ts 					道具表
this.use_switch_gift = function()
	local t_params = ngx.ctx.t_params
	local n_code
	local n_beItemId, n_price = t_params.beitem_id, 0
	local s_items
	local ts_desc, t_items, t_itemsMaidian
	local n_useNum = t_params.num
	local n_costItemId
	local is_lucky = false
	local n_lucky_val = 0
	local has_big_reward = false

	-- 数目校验
	if n_useNum <= 0 then
		ts_desc = 'num less than 0'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	local n_giftId =  mis_data.t_gift.t_beitem2gift[n_beItemId]
	if not n_giftId then
		ts_desc = 'beitem_id not found'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包存在性判定
	local t_giftConf = mis_data.t_gift.t_conf[n_giftId]
	if not t_giftConf then
		ts_desc = 'conf not found'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 是否抽奖礼包
	if t_giftConf.switch_pack ~= 1 then
		ts_desc = 'not switch_pack'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 计算随机礼包道具
	local skin_info = mis_bridge.query_owned_skin_account(t_params.uin)
	local avatar_info = mis_bridge.query_owned_avatar_account(t_params.uin)
	t_items = mis_bridge.use_prop(skin_info, avatar_info, n_useNum, t_giftConf.switch_id, t_giftConf.switch_id_num, t_giftConf.probability, t_giftConf.switch_tag, t_giftConf.switch_skin)

	-- 扣费
	n_code, ts_desc = mis_bridge.cost_money(t_params.uin, t_giftConf.Beitem, n_useNum, mis_config.t_costType.n_ITEM, 'use_switch_gift'
		, mis_common.table_to_json({aname = 'use_switch_gift',gift_id = n_giftId, gift_type = t_giftConf.GiftType}))
	if n_code ~= t_retCode.n_OK then
		mis_log.day('gift_error', 'use_switch_gift_sub_items|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
			(t_giftConf.Beitem or 'null') .. '|' .. n_useNum)
		return n_code, ts_desc
	end

	--- 扣费成功后计算幸运值道具 fix bugs：扣费失败仍然增加幸运值
	if t_giftConf.is_lucky == 1 then
		is_lucky = true
		n_lucky_val = this.get_user_lucky_info(t_giftConf.ID)
		mis_log.remote_day("lucky_info", "User:"..t_params.uin.."|Before UseItem Lucky:"..n_lucky_val.."|UseID:"..(t_giftConf.ID).."|UseCount="..n_useNum)
	end

	if is_lucky then
		local t_big_reward = {}
		local i = 1
		for k in string.gmatch(t_giftConf.big_reward, "%d+") do
			t_big_reward[i] = tonumber(k)
			i = i + 1
		end

		--解析ItemID 与皮肤ID对应关系
		local json_str = t_giftConf.award_skin
		local item2skin = mis_common.json_to_table(json_str)

		for k, v in pairs(t_items) do
			if t_big_reward == nil or mis_common.tableIsEmpty(t_big_reward) then
				break
			end

			for sub_k, sub_v in pairs(t_big_reward) do
				if (tonumber(v.id) or 0) == tonumber(sub_v) and tonumber(v.num) > 0 then
					has_big_reward = true
					break
				end
			end

			if has_big_reward then
				break
			end
		end

		-- 随机获取了大奖 需要set n_lucky_val=0
		if has_big_reward then
			n_lucky_val = 0
			mis_log.remote_day("lucky_info", "User:"..t_params.uin.."| GetBigReward Reset Lucky:0")
		else
			-- 没有获取大奖，增加幸运值
			n_lucky_val = n_lucky_val + n_useNum

			-- 累计满100幸运值，发送大奖
			if n_lucky_val >= 100 then
				--遍历大奖 看看是否已拥有
				local vaild_reward_list = {}
				local count_skin = 1
				for reward_k, reward_v in pairs(t_big_reward) do
					local has_skin_flag = false
					local cur_reward_SkinID = item2skin[tostring(reward_v)]
					if cur_reward_SkinID == nil then
						mis_log.error("Configure is Error! cannot find["..tostring(reward_v).."] skin details")
						-- 如果没有配置相应的Item对应的 SkinID 就把SkinID置为0
						cur_reward_SkinID = 0
					end

					for k, v  in pairs(skin_info) do
						if v.ExpireTime == -1 and v.SkinID == tonumber(cur_reward_SkinID) then
							-- 拥有此永久皮肤
							has_skin_flag = true
							mis_log.remote_day("lucky_info", "User:"..t_params.uin.."| LuckyVal:"..n_lucky_val.." has over 100, but has already get BigReward:"..v.SkinID)
							break
						end
					end

					if has_skin_flag == false then
						vaild_reward_list[count_skin] = tonumber(reward_v)
						count_skin = count_skin + 1
						--mis_log.debug("player_id["..tostring(t_params.uin).."] AddSkinInRollPoll[SkinID:"..tostring(reward_v).."] and count ="..tostring(count_skin))
					end

					has_skin_flag = false
				end

				math.randomseed( ngx.now() )

				if #vaild_reward_list == 0 then
					-- 大奖都拥有了，无法进行下发，幸运值保持99
					n_lucky_val = 99
					-- mis_log.debug("player_id["..tostring(t_params.uin).."] AlreadyHasBigReward, lucky over 100")
				else
					-- 随机抽取一个大奖 下发
					local reward_id = math.random(1, #vaild_reward_list)
					reward_id = tonumber(vaild_reward_list[reward_id])

					-- mis_log.debug("player_id["..tostring(t_params.uin).."] Player:LuckyVal100 rand:"..tostring(reward_id))
					table_insert(t_items, {id = reward_id, num = 1})

					-- 减少100幸运值，如果减少后依然大于100 保持为99
					n_lucky_val = n_lucky_val - 100
					if n_lucky_val >= 100 then
						n_lucky_val = 99
					end

					mis_log.remote_day("lucky_info", "User:"..t_params.uin.."| LuckyValResult:"..n_lucky_val.."Player Get BigReward:["..reward_id.."]through lucky over 100, item_list:"..mis_common.table_to_json(t_items))
				end
			end
		end
		-- 存储当前幸运值
		mis_log.remote_day("lucky_info", "User:"..t_params.uin.."|SaveLuckyInfo, ID:"..t_giftConf.ID.."|LuckyVal:"..n_lucky_val)
		this.set_user_lucky_info( t_giftConf.ID, n_lucky_val)
	end

	-- 没有任何道具可以获得
	if #t_items == 0 then
		return t_retCode.n_OPER_ERR, 'all items have had'
	end

	-- 发送道具
	n_code, ts_desc, s_items = mis_data.add_items(t_params.uin, t_items, mis_config.t_workType.s_GIFT, 'use_switch_gift')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('gift_error', 'use_switch_gift_add_items|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
			(t_giftConf.Beitem or 'null') .. '|' .. n_useNum .. '|' .. s_items)
		return n_code, ts_desc
	end

	-- 埋点
	n_costItemId = t_giftConf.Beitem
	n_price= n_useNum
	t_items.giftId = n_giftId
	t_itemsMaidian = t_items
	if is_lucky then
		mis_log.remote_day('gift', 'ok_use|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' .. t_params.country .. '|' ..
			t_params.lang .. '|' .. n_giftId .. '|' .. t_giftConf.title .. '|' .. mis_common.table_to_json(t_itemsMaidian) .. '|' ..
			(t_giftConf.RefreshType or 'nil') .. '|' .. t_giftConf.tag .. '|' .. t_giftConf.CostType .. '|' .. n_price .. '|' .. (n_costItemId or 'nil') .. '|' .. t_giftConf.GiftType
			.. '|' .. n_lucky_val)
	else
		mis_log.remote_day('gift', 'ok_use|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' .. t_params.country .. '|' ..
			t_params.lang .. '|' .. n_giftId .. '|' .. t_giftConf.title .. '|' .. mis_common.table_to_json(t_itemsMaidian) .. '|' ..
			(t_giftConf.RefreshType or 'nil') .. '|' .. t_giftConf.tag .. '|' .. t_giftConf.CostType .. '|' .. n_price .. '|' .. (n_costItemId or 'nil') .. '|' .. t_giftConf.GiftType)
	end
	-- 客户端会判定n_giftId  老版本兼容不能返回新的键值
	-- t_items.luckyVal = n_lucky_val

	return t_retCode.n_OK, t_items
end

--------------------------------------------------------------
-- 说明：选择礼包购买
-- 参数：id 					礼包id
-- 返回：n					状态码
--		ts 					道具表
this.buy_select_gift = function()
	local t_params = ngx.ctx.t_params
	local n_code
	local n_giftId, n_price, n_now = t_params.id, 0, ngx.time()
	local s_items
	local t_, t_2, ts_desc, t_items, t_itemsMaidian, t_userGift,t_userGift2, t_sysGift, t_user
	local t_giftConf = mis_data.t_gift.t_conf[n_giftId]
	local n_buyNum = t_params.num or 1
	local n_itemId = t_params.propid
	local n_costItemId

	-- 礼包存在性判定
	if not t_giftConf then
		ts_desc = 'conf not found'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包类型判定
	if t_giftConf.GiftType ~= mis_config.t_giftPackType.n_SELECT_PACK then
		ts_desc = 'not select pack'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 是否当前礼包中可选道具
	local b_valid = false
	for _, _id in pairs(t_giftConf.t_contentId) do
		if _id == n_itemId then
			b_valid = true
			break
		end
	end

	if b_valid ~= true then
		ts_desc = 'error itemid'..n_itemId..mis_common.table_to_json(t_giftConf.t_contentId)
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包时效性判定
	-- 系统礼包的状态刷新时间精度是分钟,所以不能用在这里
	if n_now < t_giftConf.BeginTime or n_now > t_giftConf.EndTime then
		return t_retCode.n_OPER_ERR, 'expired'
	end

	-- 购买限购礼包合法性判定
	if t_giftConf.Limit then
		-- 获取个人礼包数据(只存储限购礼包数据)
		t_user = mis_data.get_user()
		n_code, t_userGift, t_userGift2 = t_user:get_gift_data()
		if n_code ~= t_retCode.n_OK then
			return n_code, t_userGift
		end
		t_ = t_userGift[n_giftId]

		-- 限购礼包数据刷新
		if t_giftConf.b_refresh then
			-- 获取系统礼包数据(获得限购礼包刷新时间)
			n_code, t_sysGift = mis_data.get_user(0):get_gift_data(true)
			if n_code ~= t_retCode.n_OK then
				return n_code, t_sysGift
			end
			t_2 = t_sysGift[n_giftId]
			if t_ and t_2 and t_.freshTime < t_2.freshTime then
				-- 刷新个人礼包数据(限购解锁)
				t_.status = band(t_2.status, bnot(mis_config.t_giftStatus.n_SOLD_OUT))
				t_.count = 0
				t_.freshTime = t_2.freshTime
			end
		end

		if t_ and band(t_.status, mis_config.t_giftStatus.n_SOLD_OUT) ~= 0 then
			-- 限购锁定
			return t_retCode.n_OPER_ERR, 'sold out'
		end
	end

	-- 道具重复性判定和计算价格
	n_price = t_giftConf.t_price[n_itemId] * n_buyNum

	-- 扣费
	if t_giftConf.CostType ~= mis_config.t_costType.n_FREE then
		n_price = math_max(0, math_ceil(n_price))
		n_code, ts_desc = mis_bridge.cost_money(t_params.uin, t_giftConf.ItemID, n_price, t_giftConf.CostType, 'buy_select_gift'
			,mis_common.table_to_json({aname = 'buy_select_gift',gift_id = n_giftId, gift_type = t_giftConf.GiftType}))
		if n_code ~= t_retCode.n_OK then
			mis_log.day('gift_error', 'buy_select_gift_cost_money|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
				(t_giftConf.ItemID or 'null') .. '|' .. n_price)
			return n_code, ts_desc
		end
	end

	t_items = {{id = n_itemId, num = n_buyNum}}

	-- 发送道具
	t_items.giftId = nil
	n_code, ts_desc, s_items = mis_data.add_items(t_params.uin, t_items, mis_config.t_workType.s_GIFT, 'buy_select_gift')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('gift_error', 'buy_select_gift_add_items|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
			(t_giftConf.ItemID or 'null') .. '|' .. n_price .. '|' .. s_items)
		return n_code, ts_desc
	end
	t_items.giftId = n_giftId

	-- 刷新个人礼包数据(针对限购礼包)
	if t_giftConf.Limit then
		if not t_userGift[n_giftId] then
			t_userGift[n_giftId] = {
				status = mis_config.t_giftStatus.n_OK;
				count = n_buyNum;
				-- 只有带刷新时间的限购礼包才有freshTime
				freshTime = t_giftConf.b_refresh and t_sysGift[n_giftId].freshTime or nil;
			}
		else
			t_userGift[n_giftId].count = t_userGift[n_giftId].count + n_buyNum
		end
		if t_userGift[n_giftId].count >= t_giftConf.Limit then
			t_userGift[n_giftId].status = bor(t_userGift[n_giftId].status, mis_config.t_giftStatus.n_SOLD_OUT)
		end
		t_user:set_gift_data(t_userGift, t_userGift2)
	end

	-- 本地记录
	if t_giftConf.CostType == mis_config.t_costType.n_ITEM then n_costItemId =  t_giftConf.ItemID end
	t_itemsMaidian = {{id = n_itemId, num = n_buyNum, price = t_giftConf.t_price[n_itemId]}}
	mis_log.remote_day('gift', 'ok_buy|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' .. t_params.country .. '|' ..
		t_params.lang .. '|' .. n_giftId .. '|' .. t_giftConf.title .. '|' .. mis_common.table_to_json(t_itemsMaidian) .. '|' ..
		(t_giftConf.RefreshType or 'nil') .. '|' .. t_giftConf.tag .. '|' .. t_giftConf.CostType .. '|' .. n_price .. '|' .. (n_costItemId or 'nil') .. '|' .. t_giftConf.GiftType)

	-- [降级控制中]
	-- 通知福利服更新福利条件
	if mis_config.n_debug ~= 0 then
		n_code, ts_desc = mis_bridge.notify_ma_buy_gift(t_params.uin, n_giftId)
		if n_code ~= t_retCode.n_OK then
			mis_log.day('gift_error', 'buy_select_gift_notify|' .. t_params.uin .. '|' .. n_giftId)
			return n_code, ts_desc
		end
	end

	return t_retCode.n_OK, t_items
end

--------------------------------------------------------------
-- 说明：礼包购买
-- 参数：id 					礼包id
-- 返回：n					状态码
--		ts 					道具表
this.buy_gift = function()
	local t_params = ngx.ctx.t_params
	local n_, n_code
	local n_giftId, n_price, n_now = t_params.id, 0, ngx.time()
	local s_items
	local t_, t_2, ts_desc, t_items, t_itemsMaidian, t_userGift,t_userGift2, t_sysGift, t_user
	local t_giftConf = mis_data.t_gift.t_conf[n_giftId]
	local n_buyNum = t_params.num or 1
	local n_costItemId

	-- 礼包存在性判定
	if not t_giftConf then
		ts_desc = 'conf not found'
		mis_log.error(ts_desc)
		return t_retCode.n_OPER_ERR, ts_desc
	end

	-- 礼包时效性判定
	-- 系统礼包的状态刷新时间精度是分钟,所以不能用在这里
	if n_now < t_giftConf.BeginTime or n_now > t_giftConf.EndTime then
		return t_retCode.n_OPER_ERR, 'expired'
	end

	-- 购买限购礼包合法性判定
	if t_giftConf.Limit then
		-- 获取个人礼包数据(只存储限购礼包数据)
		t_user = mis_data.get_user()
		n_code, t_userGift, t_userGift2 = t_user:get_gift_data()
		if n_code ~= t_retCode.n_OK then
			return n_code, t_userGift
		end
		t_ = t_userGift[n_giftId]

		-- 限购礼包数据刷新
		if t_giftConf.b_refresh then
			-- 获取系统礼包数据(获得限购礼包刷新时间)
			n_code, t_sysGift = mis_data.get_user(0):get_gift_data(true)
			if n_code ~= t_retCode.n_OK then
				return n_code, t_sysGift
			end
			t_2 = t_sysGift[n_giftId]
			if t_ and t_2 and t_.freshTime < t_2.freshTime then
				-- 刷新个人礼包数据(限购解锁)
				t_.status = band(t_2.status, bnot(mis_config.t_giftStatus.n_SOLD_OUT))
				t_.count = 0
				t_.freshTime = t_2.freshTime
			end
		end

		if t_ and band(t_.status, mis_config.t_giftStatus.n_SOLD_OUT) ~= 0 then
			-- 限购锁定
			return t_retCode.n_OPER_ERR, 'sold out'
		end
	end

	-- 道具重复性判定和计算价格
	n_price = t_giftConf.Cost
	if t_giftConf.CostType == mis_config.t_costType.n_COIN then
		n_code, ts_desc = mis_bridge.check_item_exist(t_params.uin, mis_common.table_to_json(t_giftConf.t_contentId))
		if n_code ~= t_retCode.n_OK then
			return n_code, ts_desc
		end
		t_items = {}; t_itemsMaidian = {}; n_ = 1
		for _, t_ in pairs(ts_desc) do
			if t_.canget then
				t_items[n_] = t_giftConf.t_content.t_data[t_.itemid]
				t_itemsMaidian[n_] = t_giftConf.t_contentMaidian[t_.itemid]
				n_ = n_ + 1
			else
				n_price = n_price - t_giftConf.t_price[t_.itemid] * t_giftConf.Discount
			end
		end
	else
		t_items = t_giftConf.t_content.t_data
		t_items.giftId = nil
		t_itemsMaidian = t_giftConf.t_contentMaidian
	end

	-- 道具* n_buyNum
	for _, t_ in pairs(t_items) do
		if(type(t_) == 'table') then
			t_.num = t_.num * n_buyNum
		end
	end
	for _, t_ in pairs(t_itemsMaidian) do
		if(type(t_) == 'table') then
			t_.num = t_.num * n_buyNum
		end
	end

	-- 没有任何道具可以购买
	if #t_items == 0 then
		return t_retCode.n_OPER_ERR, 'all items have had'
	end

	-- 扣费
	if t_giftConf.CostType ~= mis_config.t_costType.n_FREE then
		n_price = math_max(0, math_ceil(n_price)) * n_buyNum
		n_code, ts_desc = mis_bridge.cost_money(t_params.uin, t_giftConf.ItemID, n_price, t_giftConf.CostType,
								'buy_gift', mis_common.table_to_json({aname = 'buy_gift', gift_id = n_giftId, gift_type = t_giftConf.GiftType}))
		if n_code ~= t_retCode.n_OK then
			mis_log.day('gift_error', 'buy_gift_cost_money|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
				(t_giftConf.ItemID or 'null') .. '|' .. n_price)
			return n_code, ts_desc
		end
	end

	-- 发送道具
	n_code, ts_desc, s_items = mis_data.add_items(t_params.uin, t_items, mis_config.t_workType.s_GIFT, 'buy_gift')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('gift_error', 'buy_gift_add_items|' .. t_params.uin .. '|' .. n_giftId .. '|' .. t_giftConf.CostType .. '|' ..
			(t_giftConf.ItemID or 'null') .. '|' .. n_price .. '|' .. s_items)
		return n_code, ts_desc
	end
	t_items.giftId = n_giftId

	-- 刷新个人礼包数据(针对限购礼包)
	if t_giftConf.Limit then
		if not t_userGift[n_giftId] then
			t_userGift[n_giftId] = {
				status = mis_config.t_giftStatus.n_OK;
				count = n_buyNum;
				-- 只有带刷新时间的限购礼包才有freshTime
				freshTime = t_giftConf.b_refresh and t_sysGift[n_giftId].freshTime or nil;
			}
		else
			t_userGift[n_giftId].count = t_userGift[n_giftId].count + n_buyNum
		end
		if t_userGift[n_giftId].count >= t_giftConf.Limit then
			t_userGift[n_giftId].status = bor(t_userGift[n_giftId].status, mis_config.t_giftStatus.n_SOLD_OUT)
		end
		t_user:set_gift_data(t_userGift, t_userGift2)
	end

	-- 本地记录
	if t_giftConf.CostType == mis_config.t_costType.n_ITEM then n_costItemId =  t_giftConf.ItemID end
	mis_log.remote_day('gift', 'ok_buy|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' .. t_params.country .. '|' ..
		t_params.lang .. '|' .. n_giftId .. '|' .. t_giftConf.title .. '|' .. mis_common.table_to_json(t_itemsMaidian) .. '|' ..
		(t_giftConf.RefreshType or 'nil') .. '|' .. t_giftConf.tag .. '|' .. t_giftConf.CostType .. '|' .. n_price .. '|' .. (n_costItemId or 'nil') .. '|' .. (t_giftConf.GiftType or 'nil'))

	-- [降级控制中]
	-- 通知福利服更新福利条件
	if mis_config.n_debug ~= 0 then
		n_code, ts_desc = mis_bridge.notify_ma_buy_gift(t_params.uin, n_giftId)
		if n_code ~= t_retCode.n_OK then
			mis_log.day('gift_error', 'buy_gift_notify|' .. t_params.uin .. '|' .. n_giftId)
			return n_code, ts_desc
		end
	end

	return t_retCode.n_OK, t_items
end

--------------------------------------------------------------
-- 说明：get_user_lucky_val 获取用户所有幸运值商品对应幸运值
-- 参数：nil
-- 返回：n					状态码
--		ts 					幸运值列表
this.get_user_lucky_val = function()
	local t_user = mis_data.get_user()

	local n_code, ts = t_user:get_lucky_val_data()
	return n_code, ts
end

-- get_user_lucky_info 获取指定盒子ID对应的幸运值
this.get_user_lucky_info = function(box_idx)
	local t_user = mis_data.get_user()

	local code, data_ = t_user:get_lucky_val_data()

	if code ~= t_retCode.n_OK or code == t_retCode.n_NO_DATA or mis_common.tableIsEmpty(data_) then
		return 0
	end

	if data_[box_idx] == nil then
		return 0
	end

	return data_[box_idx]
end

-- 覆盖设置玩家盒子ID对应的幸运值
this.set_user_lucky_info = function(box_idx, lucky_val)
	local t_user = mis_data.get_user()

	local code, whole_data_ = t_user:get_lucky_val_data()

	whole_data_[box_idx] = lucky_val


	t_user:set_lucky_data(whole_data_)
end

--------------------------------------------------------------
-- 说明：回流事件触发核心
-- 参数：n_event 			事件id
-- 返回：n					状态码
--		sn 					描述
local function back_event_core(n_event)
	local t_params = ngx.ctx.t_params
	local b_update = false
	local n_offset, n_now = mis_config.t_backStatus.n_OFFSET, ngx.time()
	local t_backConf, t_misStatus, t_misConfCell = mis_data.t_back.t_conf, mis_config.t_missionStatus

	local t_user = mis_data.get_user()
	local n_code, t_backData = t_user:get_back_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end

	for n_id, t_mis in pairs(t_backData.missionEvent[n_event]) do
		t_misConfCell = t_backConf.t_mission[n_id]
		if not t_mis.status then
			b_update = true
			if t_mis.idx then t_misConfCell = t_misConfCell[t_mis.idx] end
			t_mis.value = t_mis.value and t_mis.value + 1 or 1
			-- 任务完成
			if t_mis.value >= t_misConfCell.n_target then
				t_mis.status = t_misStatus.n_DONE
					-- 关闭事件通道
				t_backData.status = bor(t_backData.status, lshift(1, n_event+n_offset))
				mis_log.remote_day('back', 'mission_complete|' .. t_params.uin .. '|' .. n_id .. '|' ..
					math_max(t_backData.startTime + t_backConf.n_missionTime - n_now, 0) .. '|' ..
					t_params.p .. '|' .. t_params.a .. '|' .. t_params.v .. '|' .. t_params.c)
			end
		elseif t_mis.status == t_misStatus.n_DONE then
			if t_misConfCell.b_heir then
				b_update = true
				if t_mis.value < t_misConfCell.n_top then
					-- 如果累计值还没有到达顶点，继续累加
					t_mis.value = t_mis.value + 1
				else
					t_backData.status = bor(t_backData.status, lshift(1, n_event+n_offset))
				end
			end
		end
	end

	if b_update then
		local n_code, s_desc = t_user:set_back_data(t_backData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：back业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_back = function()
	if mis_data.t_back.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'back disable'
	end
	local t_user = mis_data.get_user()
	if t_user:check_twoback_data_is_have(true) then
		log.day_list("twoback","pre_back-flag-1",'有二期回流数据走新回流',ngx.ctx.t_params.uin)
		return t_retCode.n_NO_DATA
	end

	if mis_data.check_user_ver_to_new() then

		if t_user:check_twoback_data_is_have_two(true) == false then
			log.day_list("twoback","pre_back-flag-2",'新版本先走新回流',ngx.ctx.t_params.uin)
			return t_retCode.n_NO_DATA
		else
			--在判断下是否能走二期了
			if t_user:check_twoback_or_oneback() then
				log.day_list("twoback","pre_back-flag-3",'新版本2先走新回流',ngx.ctx.t_params.uin)
				return t_retCode.n_NO_DATA
			end
		end
		
	end

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：查询回归状态
-- 返回：n					状态码
--		ts 					描述
this.back_status = function()
	local t_params = ngx.ctx.t_params
	local n_now, n_code, n_idx = ngx.time()
	local b_first
	local t_user, t_backData, t_ret
	local t_backConf, t_backStatus = mis_data.t_back.t_conf, mis_config.t_backStatus
	local t_backMisConf, t_stepTypeConf = t_backConf.t_mission, mis_config.t_backStepType
	local _desc

	t_user = mis_data.get_user()
	n_code, t_backData = t_user:get_back_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end

	-- 黑名单检查
	if not t_backData.black then
		-- 查询数据库
		n_code, _desc = t_user:is_black()
		if n_code ~= t_retCode.n_OK then
			return t_retCode.n_DB_ERR, 'check black failed'
		end
		t_backData.black = _desc
		if t_backData.black == 1 then
			n_code, _desc = t_user:set_back_data(t_backData)
			if n_code ~= t_retCode.n_OK then
				return n_code, _desc
			end
		end
	end
	if t_backData.black == 1 then
		return t_retCode.n_AUTH_ERR, 'black'
	end

	-- 回归系统状态判定
	if not t_backData.loginTime then
		-- 查询数据库
		n_code, _desc = t_user:get_user_basic()
		if n_code == t_retCode.n_NO_DATA then
			t_backData.loginTime = n_now
		elseif n_code == t_retCode.n_OK then
			t_backData.loginTime = tonumber(_desc.last_login_time) or n_now
		else
			return n_code, _desc
		end
	else
		-- 2021-6/1之后就可以删除这行
		t_backData.loginTime = tonumber(t_backData.loginTime)
	end

	-- 激活
	if t_backConf.n_lostTime < n_now - t_backData.loginTime then
		b_first = true
		-- 重新初始化上一次回归的数据
		t_user:new_back_data(t_backData)
		t_backData.status = bor(t_backStatus.n_INIT, t_backStatus.n_RUNING)
		t_backData.startTime = n_now
		mis_log.remote_day('back', 'activate|' .. t_params.uin .. '|' .. t_backData.loginTime .. '|' .. n_now .. '|' .. t_params.p ..
			'|' .. t_params.a .. '|' .. t_params.v .. '|' .. t_params.c)
	end

	if band(t_backData.status, t_backStatus.n_RUNING) ~= 0 then
		-- 关闭任务
		if band(t_backData.status, t_backStatus.n_MISSION) == 0 and t_backConf.n_missionTime <= n_now - t_backData.startTime then
			t_backData.status = bor(t_backData.status, t_backStatus.n_MISSION)
		end
		-- 关闭回归
		if band(t_backData.status, t_backStatus.n_RUNING) ~= 0 and t_backConf.n_showTime <= n_now - t_backData.startTime then
			t_backData.status = band(t_backStatus.n_INIT, bnot(t_backStatus.n_RUNING))
		end
		-- 任务刷新
		if band(t_backData.status, t_backStatus.n_MISSION) == 0 and mis_common.is_another_day(t_backData.loginTime, n_now) then
			-- 刷新每日任务和随机任务，无论是否完成
			for n_id, t_mis in pairs(t_backData.mission) do
				if t_backMisConf[n_id].b_recycle then
					t_mis.value = nil; t_mis.status = nil
					t_backData.status = band(t_backData.status, bnot(lshift(1, t_backMisConf[n_id].n_event+t_backStatus.n_OFFSET)))
				elseif t_backMisConf[n_id].n_stepType == t_stepTypeConf.n_RANDOM then
					n_idx = math_random(1, #t_backMisConf[n_id])
					t_backData.mission[n_id] = {idx = n_idx}
					t_backData.missionEvent[t_backMisConf[n_id].n_event][n_id] = t_backData.mission[n_id]
					t_backData.status = band(t_backData.status, bnot(lshift(1, t_backMisConf[n_id].n_event+t_backStatus.n_OFFSET)))
				end
			end
			-- 触发事件
			back_event_core(mis_config.t_backEvent.n_SIGN)
			back_event_core(mis_config.t_backEvent.n_LOGIN)
			back_event_core(mis_config.t_backEvent.n_TOTAL_LOGIN)
		end
	end

	t_ret = {
		status = bor(t_backData.status, b_first and t_backStatus.n_FIRST or 0);
		interval = b_first and n_now - t_backData.loginTime or nil;
	}

	t_backData.loginTime = n_now
	n_code, _desc = t_user:set_back_data(t_backData)
	if n_code ~= t_retCode.n_OK then
		return n_code, _desc
	end

	return t_retCode.n_OK, t_ret
end

--------------------------------------------------------------
-- 说明：拉取回归主界面数据
-- 返回：n					状态码
--		ts 					描述
this.back_main = function()
	local n_code, t_backData = mis_data.get_user():get_back_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end
	if band(t_backData.status, mis_config.t_backStatus.n_RUNING) == 0 then
		return t_retCode.n_OPER_ERR, "back system isn't running"
	end
	local n_missionTime = t_backData.startTime + mis_data.t_back.t_conf.n_missionTime - ngx.time()
	return t_retCode.n_OK, {
		status = t_backData.status;
		showTime = math_max(t_backData.startTime + mis_data.t_back.t_conf.n_showTime - ngx.time(), 0);
		missionTime = n_missionTime > 0 and n_missionTime or nil;
		score = t_backData.score;
		totalScore = t_backData.totalScore;
		progress = t_backData.progress;
		bonus = t_backData.bonus;
		mission = t_backData.mission;
	}
end

--------------------------------------------------------------
-- 说明：回归事件触发
-- 参数：event 				事件id
-- 返回：n					状态码
--		ts 					当前回归状态
this.back_event = function()
	local t_user = mis_data.get_user()
	local n_code, t_backData = t_user:get_back_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end

	if band(t_backData.status, mis_config.t_backStatus.n_RUNING) == 0 then
		return t_retCode.n_OPER_ERR, "back system isn't running"
	end
	if band(t_backData.status, mis_config.t_backStatus.n_MISSION) ~= 0 then
		return t_retCode.n_OPER_ERR, 'forbid do mission'
	end

	local t_params = ngx.ctx.t_params
	local n_code, s_desc = back_event_core(t_params.event)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- [特例]
	-- 如果是首次联机，发送奖励邮件
	if t_params.event == mis_config.t_backEvent.n_MULTI_PLAY and not t_backData.email then
		local t_mailConf = mis_config.t_backMail
		local t_backConf = mis_data.t_back.t_conf
		local n_last = t_backData.startTime + t_backConf.n_showTime - ngx.time()
		n_code, s_desc = mis_bridge.send_email(t_params.uin, t_mailConf.s_title,
							t_mailConf.s_body, n_last, t_backConf.t_mail, t_mailConf.n_jumpTo)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		t_backData.email = 1
		n_code, s_desc = t_user:set_back_data(t_backData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	return n_code, {status = t_backData.status}
end

--------------------------------------------------------------
-- 说明：领取回归任务奖励
-- 参数：id					任务id
--		idx 				奖励id
-- 返回：n					状态码
--		ts 					描述
this.back_finish = function()
	local t_params = ngx.ctx.t_params
	local n_score, n_code
	local n_id, n_idx = t_params.id, t_params.idx
	local s_desc
	local t_misCell, t_tmp, t_backData, t_user
	local t_backConf = mis_data.t_back.t_conf
	local t_misStatus = mis_config.t_missionStatus
	local t_misConfCell = t_backConf.t_mission[n_id]

	t_user = mis_data.get_user()
	n_code, t_backData = t_user:get_back_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end

	if band(t_backData.status, mis_config.t_backStatus.n_RUNING) == 0 then
		return t_retCode.n_OPER_ERR, "back system isn't running"
	end
	if band(t_backData.status, mis_config.t_backStatus.n_MISSION) ~= 0 then
		return t_retCode.n_OPER_ERR, 'forbid do mission'
	end
	t_misCell = t_backData.mission[n_id]
	if not t_misCell then
		return t_retCode.n_PARAM_ERR, 'no such mission'
	end
	if t_misConfCell.n_stepType and t_misCell.idx ~= n_idx then
		return t_retCode.n_PARAM_ERR, 'idx error'
	end
	if t_misCell.status ~= t_misStatus.n_DONE then
		return t_retCode.n_OPER_ERR, 'mission not finished'
	end

	n_score = t_misConfCell.n_score or t_misConfCell[n_idx].n_score
	t_backData.score = t_backData.score or 0
	t_backData.totalScore = t_backData.totalScore or 0
	t_backData.score = t_backData.score + n_score
	t_backData.totalScore = t_backData.totalScore + n_score

	t_misCell.status = t_misStatus.n_PICKED

	-- 判断是否刷新新任务
	if t_misConfCell.n_stepType == mis_config.t_backStepType.n_ORDER and t_misConfCell.b_heir then
		-- 有累计进度的顺序任务链
		if n_idx < #t_misConfCell then
			t_tmp = {
				value = t_misCell.value;
				idx = n_idx + 1;
				status = t_misCell.value >= t_misConfCell[n_idx+1].n_target and t_misStatus.n_DONE or nil;
			}
			t_backData.mission[n_id] = t_tmp
			t_backData.missionEvent[t_misConfCell.n_event][n_id] = t_tmp
		else
			t_backData.mission[n_id] = nil
			t_backData.missionEvent[t_misConfCell.n_event][n_id] = nil
		end
	end

	n_code, s_desc = t_user:set_back_data(t_backData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	mis_log.remote_day('back', 'mission_receive|' .. t_params.uin .. '|' .. n_id .. '|' ..
		math_max(t_backData.startTime + t_backConf.n_missionTime - ngx.time(), 0) .. '|' ..
		t_params.p .. '|' .. t_params.a .. '|' .. t_params.v .. '|' .. t_params.c)

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：回归积分兑奖
-- 参数：id					奖励id
-- 返回：n					状态码
--		ts 					描述
this.back_get_bonus = function()
	local t_params = ngx.ctx.t_params
	local n_id, n_code = t_params.id
	local s_desc
	local t_user, t_backData, ts_items
	local t_bonusConf = mis_data.t_back.t_conf.t_bonus[n_id]

	if not t_bonusConf then
		return t_retCode.n_PARAM_ERR, 'invalid id'
	end

	t_user = mis_data.get_user()
	n_code, t_backData = t_user:get_back_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end

	if band(t_backData.status, mis_config.t_backStatus.n_RUNING) == 0 then
		return t_retCode.n_OPER_ERR, "back system isn't running"
	end
	if not t_backData.score or t_backData.score < t_bonusConf.n_price then
		return t_retCode.n_OPER_ERR, 'insufficient score'
	end
	if t_backData.bonus and t_backData.bonus[n_id] and t_backData.bonus[n_id].num >= t_bonusConf.n_limit then
		return t_retCode.n_OPER_ERR, 'number limit'
	end

	-- 扣费
	t_backData.score = t_backData.score - t_bonusConf.n_price
	t_backData.bonus = t_backData.bonus or {}
	t_backData.bonus[n_id] = t_backData.bonus[n_id] or {num = 0}
	t_backData.bonus[n_id].num = t_backData.bonus[n_id].num + 1
	t_backData.record = t_backData.record or {}
	t_backData.record[#t_backData.record+1] = t_bonusConf.n_itemId .. '_' .. t_bonusConf.n_price .. '_' ..
												t_bonusConf.n_num .. '_' .. ngx.time()

	n_code, s_desc = t_user:set_back_data(t_backData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 发送道具
	ts_items = {{id=t_bonusConf.n_itemId, num=t_bonusConf.n_num}}
	n_code, s_desc, ts_items = mis_data.add_items(t_params.uin, ts_items, mis_config.t_workType.s_BACK, 'back_get_bonus')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('back', 'add_items_failed|bonus|' .. t_params.uin .. '|' .. n_id .. '|' .. t_bonusConf.n_price .. '|' .. ts_items)
		return n_code, s_desc
	end

	mis_log.remote_day('back', 'get_bonus|' .. t_params.uin .. '|' .. t_bonusConf.n_itemId .. '|' .. t_bonusConf.n_num ..
		t_bonusConf.n_price .. '|' .. n_id .. '|' .. t_params.p .. '|' .. t_params.a .. '|' .. t_params.v ..
		'|' .. t_params.c)

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：回归进度条兑奖
-- 参数：id					栏位id
--		itemId 				道具id
-- 返回：n					状态码
--		ts 					描述
this.back_get_progress = function()
	local t_params = ngx.ctx.t_params
	local n_id, n_itemId, n_code = t_params.id, t_params.itemId
	local s_desc
	local t_user, t_backData, ts_items
	local t_progressConf = mis_data.t_back.t_conf.t_progress

	t_user = mis_data.get_user()
	n_code, t_backData = t_user:get_back_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end

	if band(t_backData.status, mis_config.t_backStatus.n_RUNING) == 0 then
		return t_retCode.n_OPER_ERR, "back system isn't running"
	end
	if not t_progressConf[n_id] or (t_backData.progress and t_backData.progress[n_id]) then
		return t_retCode.n_PARAM_ERR, 'invalid id'
	end
	t_progressConf = t_progressConf[n_id]
	if not t_backData.totalScore or t_backData.totalScore < t_progressConf.n_price then
		return t_retCode.n_OPER_ERR, 'insufficient total score'
	end
	-- n_itemId可能为空，下面以t_progressConf.n_itemId为准
	if t_progressConf.t_option then
		if not n_itemId or not t_progressConf.t_option[n_itemId] then
			return t_retCode.n_PARAM_ERR, 'invalid itemId'
		end
		t_progressConf = t_progressConf.t_option[n_itemId]
	end

	-- 发送道具
	ts_items = {{id=t_progressConf.n_itemId, num=t_progressConf.n_num}}
	n_code, s_desc, ts_items = mis_data.add_items(t_params.uin, ts_items, mis_config.t_workType.s_BACK, 'back_get_progress')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('back', 'add_items_failed|progress|' .. t_params.uin .. '|' .. n_id .. '|' .. ts_items)
		return n_code, s_desc
	end

	t_backData.progress = t_backData.progress or {}
	t_backData.progress[n_id] = t_progressConf.n_itemId

	n_code, s_desc = t_user:set_back_data(t_backData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	mis_log.remote_day('back', 'progress_receive|' .. t_params.uin .. '|' .. n_id .. '|' .. n_itemId .. '|' ..
		math_max(t_backData.startTime + mis_data.t_back.t_conf.n_missionTime - ngx.time(), 0) .. '|' ..
		t_params.p .. '|' .. t_params.a .. '|' .. t_params.v .. '|' .. t_params.c)

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：拉取回归兑奖记录
-- 返回：n					状态码
--		ts 					描述
this.back_record = function()
	local n_code, t_backData = mis_data.get_user():get_back_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end
	if band(t_backData.status, mis_config.t_backStatus.n_RUNING) == 0 then
		return t_retCode.n_OPER_ERR, "back system isn't running"
	end
	return t_retCode.n_OK, t_backData.record
end

--------------------------------------------------------------
-- 说明：baoku业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_baoku = function()
	if mis_data.t_baoku.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'baoku disable'
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：拉取宝库主界面
-- 返回：n					状态码
--		ts 					描述
this.baoku_main = function()
	local t_user = mis_data.get_user()
	local n_code, t_baokuData = t_user:get_baoku_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_baokuData
	end

	local t_baokuConf = mis_data.t_baoku.t_conf.baoku
	local n_now = ngx.time()
	local b_update = false
	-- 删除已经过期或者下架的宝库
	for n_id, t_ in pairs(t_baokuData) do
		if not t_baokuConf[n_id] then
			mis_log.remote_day('baoku', 'delete|' .. ngx.ctx.t_params.uin .. '|' .. n_id .. '|' .. (t_.coin or 0))
			t_baokuData[n_id] = nil
			b_update = true
		elseif t_baokuConf[n_id].n_closeTime <= n_now then
			mis_log.remote_day('baoku', 'expire|' .. ngx.ctx.t_params.uin .. '|' .. n_id .. '|' .. (t_.coin or 0))
			t_baokuData[n_id] = nil
			b_update = true
		end
	end
	if b_update then
		local n_code, s_desc = t_user:set_baoku_data(t_baokuData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	return t_retCode.n_OK, t_baokuData
end

--------------------------------------------------------------
-- 说明：宝库兑换
-- 参数：id 					宝库id
--		subId				商品id
-- 返回：n					状态码
--		ts 					描述
this.baoku_purchase = function()
	local t_params = ngx.ctx.t_params
	local n_code, n_totalPrice, n_totalNum
	local n_id, n_subId, n_num, n_now = t_params.id, t_params.subId, t_params.num or 1, ngx.time()
	local s_desc
	local t_user, t_baokuData, t_good, t_subData, t_ret, ts_items
	local t_params, t_baokuConf = ngx.ctx.t_params, mis_data.t_baoku.t_conf.baoku

	if n_num <= 0 then
		return t_retCode.n_PARAM_ERR, 'invalid num'
	end
	if not t_baokuConf[n_id] or not t_baokuConf[n_id].t_goods[n_subId] then
		return t_retCode.n_PARAM_ERR, 'invalid id or subId'
	end

	t_user = mis_data.get_user()
	n_code, t_baokuData = t_user:get_baoku_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_baokuData
	end

	t_good = t_baokuConf[n_id].t_goods[n_subId]
	if t_baokuData[n_id] and t_baokuData[n_id][n_subId] and t_good.n_limit < t_baokuData[n_id].count[n_subId] + n_num then
		return t_retCode.n_OPER_ERR, 'num limit'
	end
	n_totalPrice = t_good.n_price * n_num
	n_totalNum = t_good.n_num * n_num
	if not t_baokuData[n_id] or t_baokuData[n_id].coin < n_totalPrice then
		return t_retCode.n_OPER_ERR, 'insufficient coin'
	end

	-- 扣费
	t_subData = t_baokuData[n_id]
	t_subData.coin = t_subData.coin - n_totalPrice
	-- 记录
	t_subData.count = t_subData.count or {}
	t_subData.count[n_subId] = t_subData.count[n_subId] and t_subData.count[n_subId] + n_num or n_num
	t_subData.record = t_subData.record or {}
	t_subData.record[#t_subData.record+1] = t_good.n_itemId .. '_' .. n_now .. '_' ..
											n_totalNum .. '_' .. n_totalPrice

	n_code, s_desc = t_user:set_baoku_data(t_baokuData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 发道具
	ts_items = {{id=t_good.n_itemId, num=n_totalNum}}
	n_code, s_desc, ts_items = mis_data.add_items(t_params.uin, ts_items, mis_config.t_workType.s_BAOKU, 'baoku')
	if n_code ~= t_retCode.n_OK then
		mis_log.remote_day('baoku', 'add_items_failed|' .. t_params.uin .. '|' .. n_id .. '|' ..
			n_subId .. '|' .. n_num .. '|' .. n_totalPrice .. '|' .. ts_items)
		return n_code, s_desc
	end

	mis_log.remote_day('baoku', 'purchase|' .. t_params.uin .. '|' .. n_id .. '|' .. t_baokuConf[n_id].n_coinId ..'|'..
		n_totalPrice .. '|' .. t_subData.coin .. '|' .. t_good.n_itemId .. '|' .. n_totalNum .. '|' ..
		t_params.apiid ..'|' .. t_params.ver .. '|' .. t_params.country .. '|' .. t_params.lang)
	-- 上报大数据
	mis_log.remote_pure_day('baokuToBigData', n_now .. '|purchase|' .. t_params.uin .. '|' .. n_id .. '|' .. t_baokuConf[n_id].n_coinId ..'|'..
		n_totalPrice .. '|' .. t_subData.coin .. '|' .. t_good.n_itemId .. '|' .. n_totalNum .. '|' ..
		t_params.apiid ..'|' .. t_params.ver .. '|' .. t_params.country .. '|' .. t_params.lang)

	t_ret = {
		baokuId = n_id;
		count = {[n_subId] = t_subData.count[n_subId]};
		coin = t_subData.coin;
		record = {t_subData.record[#t_subData.record]};
		bonus = {
			itemId = t_good.n_itemId;
			num = n_totalNum;
		}
	}
	return t_retCode.n_OK, t_ret
end

--------------------------------------------------------------
-- 说明：coop业务前置检测
-- 参数：id					活动id
--		event 				事件id
--		value 				增量
--		misId 				任务id
--		bonusId 			奖励id
-- 返回：n					状态码
--		ts 					描述
this.pre_coop = function()
	local t_params = ngx.ctx.t_params
	if mis_data.t_coop.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'coop disable'
	end
	if t_params.id then
		local t_coopConf = mis_data.t_coop.t_conf[t_params.id]
		if not t_coopConf then
			return t_retCode.n_OPER_ERR, 'invalid id'
		end
		local n_now = ngx.time();
		if n_now < t_coopConf.n_startTime or t_coopConf.n_endTime < n_now then
			return t_retCode.n_OPER_ERR, 'coop out of time'
		end
		if t_params.event then
			local n_event = t_params.event
			if not t_coopConf.t_missionEvent[n_event] or n_event == mis_config.t_coopEvent.n_FINISH then
				return t_retCode.n_OPER_ERR, 'invalid event'
			end
			if t_params.value <= 0 then
				return t_retCode.n_OPER_ERR, 'invalid value'
			end
		end
		if t_params.misId and not t_coopConf.t_mission[t_params.misId] then
			return t_retCode.n_OPER_ERR, 'invalid misId'
		end
		if t_params.bonusId and not t_coopConf.t_bonus[t_params.bonusId] then
			return t_retCode.n_OPER_ERR, 'invalid bonusId'
		end
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：获得协作状态
-- 参数：id					活动id
--		name				玩家昵称
--		lang 				语言
-- 返回：n					状态码
--		ts 					描述
this.coop_status = function()
	local t_params = ngx.ctx.t_params
	local b_update
	local n_now, n_id, n_code = ngx.time(), t_params.id
	local s_desc
	local t_, t_ret, t_coopData, t_subData, t_user
	local t_coopConf = mis_data.t_coop.t_conf

	-- 玩家数据入池
	mis_calcu.insert_train(t_params.uin, t_params.lang)

	t_user = mis_data.get_user()
	n_code, t_coopData = t_user:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopData
	end
	t_subData = t_coopData[n_id]

	-- 数据清理
	-- 清理过期活动
	for n_, t_ in pairs(t_coopData) do
		-- 如果不是当前id，并且（配置不存在或者时间不符合）
		if n_ ~= n_id and (not t_coopConf[n_] or (n_now < t_coopConf[n_].n_startTime or t_coopConf[n_].n_endTime < n_now)) then
			t_coopData[n_] = nil
			b_update = true
		end
	end
	-- 清理每日任务
	if t_subData.status == mis_config.t_coopStatus.n_BIND and mis_common.is_another_day(t_subData.time or 0, n_now) then
		t_subData.time = n_now
		if t_subData.mission then
			for n_, _ in pairs(t_subData.mission) do
				if t_coopConf[n_id].t_mission[n_].b_daily then
					t_subData.mission[n_] = nil
				end
			end
			if not next(t_subData.mission) then
				t_subData.mission = nil
			end
		end
		b_update = true
	end
	if b_update then
		n_code, s_desc = t_user:set_coop_data(t_coopData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	t_ret = {
		status = t_subData.status;
		apply = t_subData.apply;
		toApply = t_subData.toApplyHash;
		score = t_subData.score;
		coworker = t_subData.coworker;
		mission = t_subData.mission;
		bonus = t_subData.bonus;
	}

	return t_retCode.n_OK, t_ret
end

--------------------------------------------------------------
-- 说明：绑定申请
-- 参数：id					活动id
--		des 				被申请uin
--		message				留言
-- 返回：n					状态码
--		ts 					描述
this.coop_bind_apply = function()
	local t_params = ngx.ctx.t_params
	local n_id, n_uin, n_des, n_code = t_params.id, t_params.uin, t_params.des
	local s_desc
	local t_user, t_userDes, t_coopData, t_coopDataDes, t_subData, t_subDataDes

	if n_uin == n_des then
		return t_retCode.n_OPER_ERR, 'can not apply self'
	end

	t_user = mis_data.get_user(n_uin)
	n_code, t_coopData = t_user:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopData
	end
	t_subData = t_coopData[n_id]

	t_userDes = mis_data.get_user(n_des)
	n_code, t_coopDataDes = t_userDes:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopDataDes
	end
	t_subDataDes = t_coopDataDes[n_id]

	if t_subData.status ~= mis_config.t_coopStatus.n_UNBIND or t_subDataDes.status ~= mis_config.t_coopStatus.n_UNBIND then
		return t_retCode.n_OPER_ERR, 'already binded'
	end

	if not t_subData.toApplyHash then
		t_subData.toApplyHash = {}
		t_subData.toApply = {}
		t_subData.toApplyHead = 1
	end
	if not t_subDataDes.applyHash then
		t_subDataDes.applyHash = {}
		t_subDataDes.apply = {}
	end

	if #t_subDataDes.apply >= mis_config.n_coopApplyNumLimit then
		return t_retCode.n_WORK_ERR, 'apply queue full'
	end

	-- 插入被申请列表
	if not t_subDataDes.applyHash[n_uin] then
		t_subDataDes.apply[#t_subDataDes.apply+1] = {uin=n_uin, msg=t_params.msg}
		t_subDataDes.applyHash[n_uin] = #t_subDataDes.apply
		n_code, s_desc = t_userDes:set_coop_data(t_coopDataDes)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	-- 插入申请列表(循环队列)
	if not t_subData.toApplyHash[n_des] then
		if t_subData.toApplyHead > mis_config.n_coopToApplyNumLimit then
			t_subData.toApplyHead = 1
		end
		-- 覆盖
		if t_subData.toApply[t_subData.toApplyHead] then
			t_subData.toApplyHash[t_subData.toApply[t_subData.toApplyHead]] = nil
		end
		t_subData.toApply[t_subData.toApplyHead] = n_des
		t_subData.toApplyHash[n_des] = t_subData.toApplyHead
		t_subData.toApplyHead = t_subData.toApplyHead + 1
		n_code, s_desc = t_user:set_coop_data(t_coopData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：对申请处理
-- 参数：id					活动id
-- 		des 				对象uin
--		ok 					是否同意
-- 返回：n					状态码
--		ts 					通过或者拒绝后的数据
this.coop_bind_response = function()
	local t_params = ngx.ctx.t_params
	local n_id, n_uin, n_des, n_code, t_push, n_len = t_params.id, t_params.uin, t_params.des
	local s_desc
	local t_ret, t_user, t_userDes, t_coopData, t_coopDataDes, t_subData, t_subDataDes
	local t_userOther, t_coopDataOther, t_subDataOther

	t_user = mis_data.get_user(n_uin)
	n_code, t_coopData = t_user:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopData
	end
	t_subData = t_coopData[n_id]

	t_userDes = mis_data.get_user(n_des)
	n_code, t_coopDataDes = t_userDes:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopDataDes
	end
	t_subDataDes = t_coopDataDes[n_id]

	-- 申请列表可能因为队列满了之后被后来的申请覆盖，
	-- 所以这里只需要检查被申请列表和申请人的绑定状态
	if not t_subData.applyHash or not t_subData.applyHash[n_des] then
		return t_retCode.n_OPER_ERR, 'no apply'
	end
	if t_subData.status ~= mis_config.t_coopStatus.n_UNBIND then
		return t_retCode.n_OPER_ERR, 'self already binded'
	end

	if t_params.ok == 1 then
		-- 同意
		if t_subDataDes.status ~= mis_config.t_coopStatus.n_UNBIND then
			return t_retCode.n_OPER_ERR, 'des already binded'
		end
		-- 通知好友服绑定
		n_code, s_desc = mis_bridge.friend_bind_notify(n_uin, 1)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		n_code, s_desc = mis_bridge.friend_bind_notify(n_des, 1)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		-- 双方拒绝其他申请
		if #t_subData.apply > 1 then
			for _, t_other in pairs(t_subData.apply) do
				t_userOther = mis_data.get_user(t_other.uin)
				n_code, t_coopDataOther = t_userOther:get_coop_data(n_id)
				if n_code == t_retCode.n_OK then
					t_subDataOther = t_coopDataOther[n_id]
					if t_subDataOther.toApplyHash and t_subDataOther.toApplyHash[n_uin] then
						t_subDataOther.toApply[t_subDataOther.toApplyHash[n_uin]] = nil
						t_subDataOther.toApplyHash[n_uin] = nil
						if not next(t_subDataOther.toApplyHash) then
							t_subDataOther.toApply = nil
							t_subDataOther.toApplyHash = nil
							t_subDataOther.toApplyHead = nil
						end
						t_userOther:set_coop_data(t_coopDataOther)
					end
				end
			end
		end
		if t_subDataDes.apply then
			for _, t_other in pairs(t_subDataDes.apply) do
				t_userOther = mis_data.get_user(t_other.uin)
				n_code, t_coopDataOther = t_userOther:get_coop_data(n_id)
				if n_code == t_retCode.n_OK then
					t_subDataOther = t_coopDataOther[n_id]
					if t_subDataOther.toApplyHash and t_subDataOther.toApplyHash[n_uin] then
						t_subDataOther.toApply[t_subDataOther.toApplyHash[n_uin]] = nil
						t_subDataOther.toApplyHash[n_uin] = nil
						if not next(t_subDataOther.toApplyHash) then
							t_subDataOther.toApply = nil
							t_subDataOther.toApplyHash = nil
							t_subDataOther.toApplyHead = nil
						end
						t_userOther:set_coop_data(t_coopDataOther)
					end
				end
			end
		end
		t_subData.status = mis_config.t_coopStatus.n_BIND
		t_subData.coworker = n_des
		t_subData.apply = nil
		t_subData.applyHash = nil
		t_subData.toApply = nil
		t_subData.toApplyHash = nil
		t_subData.toApplyHead = nil
		t_subDataDes.status = mis_config.t_coopStatus.n_BIND
		t_subDataDes.coworker = n_uin
		t_subDataDes.apply = nil
		t_subDataDes.applyHash = nil
		t_subDataDes.toApply = nil
		t_subDataDes.toApplyHash = nil
		t_subDataDes.toApplyHead = nil
		t_ret = {accept = {coworker = n_des}}
		mis_log.day('coop', mis_common.table_to_json({
			key = 'bind';
			activity_id = n_id;
			uin = n_uin;
			des_uin = n_des;
			channel = t_params.apiid or 'null';
			version = t_params.ver or 'null';
			country = t_params.country or 'null';
			language = t_params.lang or 'null';
			ts = ngx.time();
			ip = t_params.s_remoteAddr;
		}))
	else
		-- 拒绝
		n_len = #t_subData.apply
		t_subData.apply[t_subData.applyHash[n_des]] = t_subData.apply[n_len]
		t_subData.applyHash[t_subData.apply[n_len].uin] = t_subData.applyHash[n_des]
		t_subData.apply[n_len] = nil
		t_subData.applyHash[n_des] = nil
		if #t_subData.apply == 0 then
			t_subData.apply = nil
			t_subData.applyHash = nil
		end
		-- 由于循环队列可能会被覆盖或者删除,需要检测
		if t_subDataDes.toApplyHash and t_subDataDes.toApplyHash[n_uin] then
			t_subDataDes.toApply[t_subDataDes.toApplyHash[n_uin]] = nil
			t_subDataDes.toApplyHash[n_uin] = nil
			if not next(t_subDataDes.toApplyHash) then
				t_subDataDes.toApply = nil
				t_subDataDes.toApplyHash = nil
				t_subDataDes.toApplyHead = nil
			end
		end
		t_ret = {refuse = {}}
	end

	n_code, s_desc = t_user:set_coop_data(t_coopData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	n_code, s_desc = t_userDes:set_coop_data(t_coopDataDes)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	return t_retCode.n_OK, t_ret
end

--------------------------------------------------------------
-- 说明：拉取玩家表
-- 参数：pos					位置
--		lang 				语言
-- 返回：n					状态码
--		ts 					描述
this.coop_find = function()
	local t_params = ngx.ctx.t_params
	local s_data = mis_calcu.read_train(t_params.pos, t_params.lang)
	return t_retCode.n_OK, s_data and {player = s_data}
end

--------------------------------------------------------------
-- 说明：事件触发
-- 参数：id					活动id
--		event 				事件id
-- 		value 				增量
-- 返回：n					状态码
--		ts 					是否禁止客户端上报
this.coop_event = function()
	local t_params = ngx.ctx.t_params
	local b_daily, b_update
	local n_now, n_id, n_finish, n_code = ngx.time(), t_params.id, 0
	local s_desc
	local t_user, t_coopData, t_subData
	local t_coopConf = mis_data.t_coop.t_conf[n_id]

	t_user = mis_data.get_user()
	n_code, t_coopData = t_user:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopData
	end
	t_subData = t_coopData[n_id]

	if t_subData.status ~= mis_config.t_coopStatus.n_BIND then
		return t_retCode.n_OK, 'unbind'
	end

	if not t_subData.mission then
		t_subData.mission = {}
	end

	-- 推进普通任务
	for _, t_ in pairs(t_coopConf.t_missionEvent[t_params.event]) do
		if not t_subData.mission[t_.n_id] then
			t_subData.mission[t_.n_id] = {value = 0}
		end
		if not t_subData.mission[t_.n_id].status then
			b_update = true
			t_subData.mission[t_.n_id].value = math_min(t_subData.mission[t_.n_id].value + t_params.value, t_.n_target)
			if t_subData.mission[t_.n_id].value == t_.n_target then
				t_subData.mission[t_.n_id].status = mis_config.t_missionStatus.n_DONE
				n_finish = n_finish + 1
				mis_log.day('coop', mis_common.table_to_json({
					key = 'complete';
					activity_id = n_id;
					uin = t_params.uin;
					mission_id = t_.n_id;
					mission_type = (t_.b_daily and 'daily' or 'activity');
					channel = t_params.apiid or 'null';
					version = t_params.ver or 'null';
					country = t_params.country or 'null';
					language = t_params.lang or 'null';
					ts = n_now;
					ip = t_params.s_remoteAddr;
				}))
			end
		else
			if t_.b_daily then b_daily = true end
		end
	end

	-- 推进自动任务
	if n_finish > 0 then
		for _, t_ in pairs(t_coopConf.t_missionAuto) do
			if not t_subData.mission[t_.n_id] then
				t_subData.mission[t_.n_id] = {value = 0}
			end
			if not t_subData.mission[t_.n_id].status then
				t_subData.mission[t_.n_id].value = math_min(t_subData.mission[t_.n_id].value + n_finish, t_.n_target)
				if t_subData.mission[t_.n_id].value == t_.n_target then
					t_subData.mission[t_.n_id].status = mis_config.t_missionStatus.n_DONE
					mis_log.day('coop', mis_common.table_to_json({
						key = 'complete';
						activity_id = n_id;
						uin = t_params.uin;
						mission_id = t_.n_id;
						mission_type = 'activity';
						channel = t_params.apiid or 'null';
						version = t_params.ver or 'null';
						country = t_params.country or 'null';
						language = t_params.lang or 'null';
						ts = n_now;
						ip = t_params.s_remoteAddr;
					}))
				end
			end
		end
	end

	if b_update then
		n_code, s_desc = t_user:set_coop_data(t_coopData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	-- 如果没有任务推进，禁止客户端上报
	return t_retCode.n_OK, not b_update and ({nextTime = b_daily and (ngx.time()+mis_common.time_to_next_day()) or -1}) or nil
end

--------------------------------------------------------------
-- 说明：领取任务积分
-- 参数：id					活动id
--		misId 				任务id
-- 返回：n					状态码
--		ts 					描述
this.coop_finish = function()
	local t_params = ngx.ctx.t_params
	local n_id, n_uin, n_misId, n_code = t_params.id, t_params.uin, t_params.misId
	local s_desc
	local t_user, t_userDes, t_coopData, t_coopDataDes, t_subData, t_subDataDes
	local t_misConf = mis_data.t_coop.t_conf[n_id].t_mission[n_misId]

	t_user = mis_data.get_user()
	n_code, t_coopData = t_user:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopData
	end
	t_subData = t_coopData[n_id]

	if t_subData.status ~= mis_config.t_coopStatus.n_BIND then
		return t_retCode.n_OPER_ERR, 'unbind'
	end
	if not t_subData.mission or not t_subData.mission[n_misId] or t_subData.mission[n_misId].status ~= mis_config.t_missionStatus.n_DONE then
		return t_retCode.n_OPER_ERR, 'can not finish'
	end

	t_userDes = mis_data.get_user(t_subData.coworker)
	n_code, t_coopDataDes = t_userDes:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopDataDes
	end
	t_subDataDes = t_coopDataDes[n_id]

	-- 双方数据不同步,删除数据
	if t_subDataDes.status ~= mis_config.t_coopStatus.n_BIND or t_subDataDes.coworker ~= n_uin then
		s_desc = 'data out of sync, score=' .. (t_subData.score or 0)
		mis_log.error(s_desc)
		n_code, s_desc = t_user:delete_coop_data()
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		return t_retCode.n_SYS_ERR, s_desc
	end

	t_subData.mission[n_misId].status = mis_config.t_missionStatus.n_PICKED
	t_subData.score = t_subData.score and t_subData.score + t_misConf.n_score or t_misConf.n_score
	t_subDataDes.score = t_subDataDes.score and t_subDataDes.score + t_misConf.n_score or t_misConf.n_score

	n_code, s_desc = t_user:set_coop_data(t_coopData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	n_code, s_desc = t_userDes:set_coop_data(t_coopDataDes)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	mis_log.day('coop', mis_common.table_to_json({
		key = 'finish';
		activity_id = n_id;
		uin = n_uin;
		des_uin = t_subData.coworker;
		mission_id = n_misId;
		mission_type = (t_misConf.b_daily and 'daily' or 'activity');
		score = t_misConf.n_score;
		channel = t_params.apiid or 'null';
		version = t_params.ver or 'null';
		country = t_params.country or 'null';
		language = t_params.lang or 'null';
		ts = ngx.time();
		ip = t_params.s_remoteAddr;
	}))

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：领取奖励
-- 参数：id 					活动id
--		bonusId				奖励id
-- 返回：n 					状态码
--		ts 					奖励列表
this.coop_bonus = function()
	local t_params = ngx.ctx.t_params
	local n_id, n_bonusId, n_code = t_params.id, t_params.bonusId
	local s_items, s_desc
	local t_user, t_coopData, t_subData
	local t_bonusConf = mis_data.t_coop.t_conf[n_id].t_bonus[n_bonusId]

	t_user = mis_data.get_user()
	n_code, t_coopData = t_user:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopData
	end
	t_subData = t_coopData[n_id]

	if t_subData.status ~= mis_config.t_coopStatus.n_BIND then
		return t_retCode.n_OPER_ERR, 'unbind'
	end
	if t_subData.bonus and t_subData.bonus[n_bonusId] then
		return t_retCode.n_OPER_ERR, 'already picked'
	end
	if not t_subData.score or t_subData.score < t_bonusConf.n_score then
		return t_retCode.n_OPER_ERR, 'insufficient score'
	end

	if not t_subData.bonus then t_subData.bonus = {} end
	t_subData.bonus[n_bonusId] = 1

	n_code, s_desc = t_user:set_coop_data(t_coopData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 发送道具
	n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_bonusConf.t_data, mis_config.t_workType.s_COOP, 'coop_get_bonus')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('coop', 'add_items_failed|' .. t_params.uin .. '|' .. n_bonusId .. '|' .. s_items)
		return n_code, s_desc
	end

	mis_log.day('coop', mis_common.table_to_json({
		key = 'bonus';
		activity_id = n_id;
		uin = t_params.uin;
		bonus = t_bonusConf.t_data;
		need_score = t_bonusConf.n_score;
		channel = t_params.apiid or 'null';
		version = t_params.ver or 'null';
		country = t_params.country or 'null';
		language = t_params.lang or 'null';
		ts = ngx.time();
		ip = t_params.s_remoteAddr;
	}))

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：取消绑定
-- 参数：id 					活动id
-- 返回：n					状态码
--		ts 					描述
this.coop_unbind = function()
	local t_params = ngx.ctx.t_params
	local n_id, n_code, n_des = t_params.id
	local s_desc
	local t_user, t_userDes, t_coopData, t_coopDataDes, t_subData, t_subDataDes

	t_user = mis_data.get_user()
	n_code, t_coopData = t_user:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopData
	end
	t_subData = t_coopData[n_id]

	if t_subData.status ~= mis_config.t_coopStatus.n_BIND then
		return t_retCode.n_OPER_ERR, 'unbind'
	end
	n_des = t_subData.coworker

	t_userDes = mis_data.get_user(n_des)
	n_code, t_coopDataDes = t_userDes:get_coop_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_coopDataDes
	end
	t_subDataDes = t_coopDataDes[n_id]

	-- 通知好友服解除绑定
	n_code, s_desc = mis_bridge.friend_bind_notify(t_params.uin, 0)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	-- 数据清理
	t_coopData[n_id] = {
		status = mis_config.t_coopStatus.n_UNBIND;
		bonus = t_subData.bonus;
	}
	n_code, s_desc = t_user:set_coop_data(t_coopData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 镜像操作
	if t_subDataDes.coworker == t_params.uin then
		n_code, s_desc = mis_bridge.friend_bind_notify(n_des, 0)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		t_coopDataDes[n_id] = {
			status = mis_config.t_coopStatus.n_UNBIND;
			bonus = t_subDataDes.bonus;
		}
		n_code, s_desc = t_userDes:set_coop_data(t_coopDataDes)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	mis_log.day('coop', mis_common.table_to_json({
		key = 'unbind';
		activity_id = n_id;
		uin = t_params.uin;
		des_uin = n_des;
		channel = t_params.apiid or 'null';
		version = t_params.ver or 'null';
		country = t_params.country or 'null';
		language = t_params.lang or 'null';
		ts = ngx.time();
		ip = t_params.s_remoteAddr;
	}))

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：有效化标签
-- 参数：t_misConf, t_misData, n_labelId
local function enable_label(t_misConf, t_misData, n_labelId)
	t_misData.label[n_labelId].status = mis_config.t_labelStatus.n_ENABLE
	if not t_misData.label[n_labelId].activateTime then
		t_misData.label[n_labelId].activateTime = ngx.time()
	end
	t_misData.taskEvent = t_misData.taskEvent or {}
	local t_taskConf = t_misConf.t_conf.t_label[n_labelId].t_task
	if t_misData.label[n_labelId].task then
		for n_taskId, t_task in pairs(t_misData.label[n_labelId].task) do
			local n_event = t_taskConf[n_taskId].n_event
			t_misData.taskEvent[n_event] = t_misData.taskEvent[n_event] or {}
			t_misData.taskEvent[n_event][n_labelId..'_'..n_taskId] = 1
		end
	end
end

--------------------------------------------------------------
-- 说明：删除标签
-- 参数：t_misData, n_labelId
local function delete_label(t_misData, n_labelId)
	if t_misData.taskEvent then
		for n_event, t_ in pairs(t_misData.taskEvent) do
			for s_key, _ in pairs(t_) do
				if n_labelId == tonumber(string_match(s_key, '(%d+)_')) then
					t_[s_key] = nil
				end
			end
		end
		for n_event, t_ in pairs(t_misData.taskEvent) do
			if not next(t_) then t_misData.taskEvent[n_event] = nil end
		end
		if not next(t_misData.taskEvent) then
			t_misData.taskEvent = nil
		end
	end
	if t_misData.label then
		t_misData.label[n_labelId].status = mis_config.t_labelStatus.n_DEAD
		t_misData.label[n_labelId] = nil
		if not next(t_misData.label) then t_misData.label = nil end
	end
end

--------------------------------------------------------------
-- 说明：无效化标签
-- 参数：t_misConf, t_misData, n_labelId
local function disable_label(t_misConf, t_misData, n_labelId)
	t_misData.label[n_labelId].status = mis_config.t_labelStatus.n_DISABLE
	if t_misData.taskEvent then
		for n_taskId, t_task in pairs(t_misConf.t_conf.t_label[n_labelId].t_task) do
			local s_key = n_labelId .. '_' .. n_taskId
				for _, t_ in pairs(t_misData.taskEvent) do
					if t_[s_key] then t_[s_key] = nil; break end
				end
		end
		for n_event, t_ in pairs(t_misData.taskEvent) do
			if not next(t_) then t_misData.taskEvent[n_event] = nil end
		end
		if not next(t_misData.taskEvent) then
			t_misData.taskEvent = nil
		end
	end
end

--------------------------------------------------------------
-- 说明：创建任务
-- 参数：t_misConf, t_misData, n_labelId, n_taskId
local function create_task(t_misConf, t_misData, n_labelId, n_taskId)
	local t_label = t_misData.label[n_labelId]
	local t_taskConf = t_misConf.t_conf.t_label[n_labelId].t_task[n_taskId]
	t_label.task = t_label.task or {}
	t_label.task[n_taskId] = {activateTime = ngx.time()}
	if type(t_taskConf.tn_target) == 'table' then
		t_label.task[n_taskId].target = t_taskConf.tn_target[1]
	end
	t_misData.taskEvent = t_misData.taskEvent or {}
	t_misData.taskEvent[t_taskConf.n_event] = t_misData.taskEvent[t_taskConf.n_event] or {}
	t_misData.taskEvent[t_taskConf.n_event][n_labelId..'_'..n_taskId] = 1
end

--------------------------------------------------------------
-- 说明：创建随机任务
-- 参数：t_misConf, t_misData, n_labelId
local function create_random_task(t_misConf, t_misData, n_labelId)
	local n_taskId, n_index
	local t_labelConf = t_misConf.t_conf.t_label[n_labelId]
	local t_label = t_misData.label[n_labelId]
	-- 过滤随机池
	local t_pool, t_pool2, n_all = nil, {}, 0
	if not t_label.random or t_label.random == 0 then
		t_pool = {
			t_labelConf.t_random.t_pool.t_first;
			t_labelConf.t_random.t_pool.t_default
		}
	else
		t_pool = {t_labelConf.t_random.t_pool.t_default}
	end
	for _, t_ in pairs(t_pool) do
		for _, t_2 in pairs(t_) do
			if t_labelConf.t_random.b_once and t_label.task and t_label.task[t_2.n_taskId] and t_label.task[t_2.n_taskId].status then
				-- 不可重复获得已完成的任务
			elseif not mis_condition.check_task(t_misConf, nil, n_labelId, t_2.n_taskId) then
				-- 任务检查不过关
			else
				n_all = n_all + t_2.n_ratio
				t_pool2[#t_pool2+1] = {n_taskId = t_2.n_taskId, n_ratio = t_2.n_ratio}
				if t_2.n_taskId == t_label.preId then n_index = #t_pool2 end
			end
		end
		if 0 < n_all then break end
	end
	if n_index and #t_pool2 > 1 then
		-- 如果随机池包含了上次随机到的任务，并且随机池数量大于1，将其过滤
		n_all = n_all - t_pool2[n_index].n_ratio
		t_pool2[n_index] = t_pool2[#t_pool2]
		t_pool2[#t_pool2] = nil
	end
	if #t_pool2 > 0 then
		-- 重新计算概率
		local n_count = 0
		for _, t_ in ipairs(t_pool2) do
			n_count = n_count + t_.n_ratio; t_.n_ratio = n_count / n_all
		end
		local n_rand = math_random()
		for _, t_ in pairs(t_pool2) do
			if n_rand <= t_.n_ratio then n_taskId = t_.n_taskId; break end
		end
		t_label.preId = n_taskId
		local t_taskConf = t_labelConf.t_task[n_taskId]
		t_label.task = t_label.task or {}
		t_label.task[n_taskId] = {activateTime = ngx.time()}
		if type(t_taskConf.tn_target) == 'table' then
			t_label.task[n_taskId].target = t_taskConf.tn_target[1]
		end
		t_misData.taskEvent = t_misData.taskEvent or {}
		t_misData.taskEvent[t_taskConf.n_event] = t_misData.taskEvent[t_taskConf.n_event] or {}
		t_misData.taskEvent[t_taskConf.n_event][n_labelId..'_'..n_taskId] = 1
	end
end

--------------------------------------------------------------
-- 说明：删除任务
-- 参数：t_misData, n_labelId, n_taskId
local function delete_task(t_misData, n_labelId, n_taskId)
	local s_key = n_labelId .. '_' .. n_taskId

	--做下判空处理
	if t_misData.taskEvent then
		for n_event, t_ in pairs(t_misData.taskEvent) do
		if t_[s_key] then
			t_[s_key] = nil
			if not next(t_) then
				t_misData.taskEvent[n_event] = nil
				if not next(t_misData.taskEvent) then
					t_misData.taskEvent = nil
				end
			end
			break
		end
	end
	end

	if t_misData.label and t_misData.label[n_labelId].task then
		t_misData.label[n_labelId].task[n_taskId] = nil
		if not next(t_misData.label[n_labelId].task) then
			t_misData.label[n_labelId].task = nil
			if not next(t_misData.label) then
				t_misData.label = nil
			end
		end
	end
end

--------------------------------------------------------------
-- 说明：领取任务奖励核心函数
--		函数将数据库写入事件和发奖励事件打包成两个函数，提供外部在适当时机调用
-- 参数：t_misData, n_labelId, n_taskId, n_bonusId
-- 返回：n 					状态码
--		s 					描述
--		f					数据库写入
--		f 					发奖励
local function mission_finish_core(t_misData, n_labelId, n_taskId, n_bonusId)
	local t_params = ngx.ctx.t_params
	local _
	local n_code
	local s_desc
	local t_bonus
	local t_labelConf = mis_data.t_mission.t_conf.t_label[n_labelId]
	local t_taskConf = t_labelConf.t_task[n_taskId]
	local t_label = t_misData.label[n_labelId]
	local t_task = t_label.task[n_taskId]

	t_task.status = mis_config.t_missionStatus.n_PICKED
	if t_labelConf.n_type == mis_config.t_labelType.n_RANDOM then
		t_bonus = t_taskConf.t_bonus
	else
		t_task.bonusId = n_bonusId
		if t_task.target and t_task.target ~= t_taskConf.tn_target[#t_taskConf.tn_target] then
			t_task.target = t_taskConf.tn_target[mis_common.table_find(t_taskConf.tn_target, t_task.target)+1]
			if t_task.value >= t_task.target then
				t_task.status = mis_config.t_missionStatus.n_DONE
			else
				t_task.status = nil
			end
		end
		if t_taskConf.t_bonus then
			t_bonus = t_taskConf.t_bonus
		elseif t_taskConf.t_selectBonus then
			t_bonus = t_taskConf.t_selectBonus[n_bonusId]
		end
	end
	t_label.finish = t_label.finish and t_label.finish + 1 or 1

	local f_1 = function()
		return mis_data.get_user():set_mission_data(t_misData)
	end
	local f_2 = function()
		n_code, s_desc, _ = mis_data.add_items(t_params.uin, t_bonus, mis_config.t_workType.s_MISSION, 'mission_finish')
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		mis_log.remote_pure_day('mission', mis_common.table_to_json({
			key = 'finish';
			ip = t_params.s_remoteAddr;
			uin = t_params.uin;
			time = ngx.time();
			country = t_params.country;
			apiid = t_params.apiid;
			ver = t_params.ver;
			lang = t_params.lang;
			labelId = n_labelId;
			taskId = n_taskId;
			bonusId = n_bonusId and tostring(n_bonusId) or 'null';
		}))
		return t_retCode.n_OK
	end

	return t_retCode.n_OK, nil, f_1, f_2
end

--------------------------------------------------------------
-- 说明：mission业务前置检测
-- 参数：createTime			注册时间
--		event 				事件id
--		value 				增量
--		labelId 			标签id
--		taskId 				任务id
--		bonusId 			奖励id
-- 返回：n					状态码
--		ts 					描述
this.pre_mission = function()
	local t_params = ngx.ctx.t_params
	local t_ = mis_data.t_mission
	if t_.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'mission disable'
	end
	if t_params.createTime and (t_params.createTime <= 0 or t_params.createTime > ngx.time()) then
		return t_retCode.n_PARAM_ERR, 'invalid createTime'
	end
	if t_params.event then
		if not t_.t_eventConf[t_params.event] then
			return t_retCode.n_PARAM_ERR, 'invalid event'
		end
		if t_params.value <= 0 then
			return t_retCode.n_PARAM_ERR, 'invalid value'
		end
	end
	if t_params.labelId then
		t_ = t_.t_conf.t_label[t_params.labelId]
		if not t_ then
			return t_retCode.n_PARAM_ERR, 'invalid labelId'
		end
		t_ = t_.t_task[t_params.taskId]
		if not t_ then
			return t_retCode.n_PARAM_ERR, 'invalid taskId'
		end
		if t_params.bonusId and (not t_.t_selectBonus or not t_.t_selectBonus[t_params.bonusId]) then
			return t_retCode.n_PARAM_ERR, 'invalid bonusId'
		elseif not t_params.bonusId and t_.t_selectBonus then
			return t_retCode.n_PARAM_ERR, 'require bonusId'
		end
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：拉取任务状态
-- 参数：createTime			注册时间
--		f_callback			回调
-- 返回：n					状态码
--		ts 					描述
this.mission_status = function(f_callback)
	local t_params = ngx.ctx.t_params
	local n_uin	= t_params.uin
	local n_bucketId, n_res, t_noviceTaskConf, n_abtestNew
	local b_update
	local n_now, n_code, n_labelId, n_taskId, n_ = ngx.time()
	local s_desc
	local t_user, t_misData, t_taskConf, t_label, t_labelConf, t_task
	local t_labelType, t_labelStatus = mis_config.t_labelType, mis_config.t_labelStatus
	local t_conf, t_misStatus, t_ret = mis_data.t_mission.t_conf, mis_config.t_missionStatus, {}


	-- 这里耦合一个需求，用户登录时更新周末好礼抽奖次数
	this.weekend_gift_login()
	this.relic_imitate_task_event(18)

	t_user = mis_data.get_user()
	n_code, t_misData = t_user:get_mission_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_misData
	end

	--[[ 旧版任务切换到新版任务的逻辑：
		1、旧版客户端必须拉取到旧版的任务；
		2、老帐号必须继续用旧版任务；
		3、ABTest不中的新玩家使用旧版任务；
		4、ABTest中的玩家使用新版任务；
		5、ABTest关闭之后，新的玩家都使用新版任务
	]]
	if not t_misData.loginTime then
		b_update = true

		if mis_data.t_novice_task 
		and mis_data.t_novice_task.t_conf 
		and not t_misData.abtest_new then
			-- 新版任务前置条件判断
			n_code, s_desc = this.pre_novice_task()
			if n_code == t_retCode.n_OK then
				t_noviceTaskConf = mis_data.t_novice_task.t_conf

				-- 默认走新版新手任务
				n_abtestNew = 1
			
				-- ABTest
				if t_noviceTaskConf.s_ABTest and string_match(t_noviceTaskConf.s_ABTest, "^%s*$") == nil then
					n_bucketId, n_res = mis_data.t_ABTestSDK.getABTestExp(t_noviceTaskConf.s_ABTest, n_uin)
					if not n_bucketId or n_res ~= 1 then
						-- ABTest不中，走旧版
						log.day_list("novice_task_ab","mission_status",n_uin,'ABTest不中',uu.to_str(n_bucketId),uu.to_str(n_res))
						n_abtestNew = 0
					else
						-- ABTest命中，走新版
						log.day_list("novice_task_ab","mission_status",n_uin,'ABTest中',uu.to_str(n_bucketId),uu.to_str(n_res))
						n_abtestNew= 1
					end
				end
				t_misData.abtest_new = n_abtestNew
			end
		end
	end

	t_ret.abtest_new = t_misData.abtest_new or 0

	-- 检查当前玩家的任务列表
	if t_misData.label then
		-- 标签检查
		for n_labelId, t_label in pairs(t_misData.label) do
			t_labelConf = t_conf.t_label[n_labelId]
			n_ = mis_condition.check_label(t_labelConf, t_label)
			if n_ == t_labelStatus.n_DELETE then
				b_update = true
				delete_label(t_misData, n_labelId)
			elseif n_ == t_labelStatus.n_ENABLE and t_label.status == t_labelStatus.n_DISABLE then
				b_update = true
				enable_label(mis_data.t_mission, t_misData, n_labelId)
			elseif n_ == t_labelStatus.n_DISABLE and t_label.status == t_labelStatus.n_ENABLE then
				b_update = true
				disable_label(mis_data.t_mission, t_misData, n_labelId)
			end
			if t_label.status == t_labelStatus.n_ENABLE then
				-- 随机机制检查
				if t_labelConf.n_type == t_labelType.n_RANDOM and not mis_condition.check_random(t_labelConf.t_random, t_misData) then
					b_update = true
					t_label.random = nil; t_label.done = nil; t_label.finish = nil; t_label.preId = nil;
				end
				if t_label.task then
					-- 任务检查(如果任务刷新,这里只删除,统一在后面重新生成)
					for n_taskId, t_task in pairs(t_label.task) do
						-- hot fix: 外网bug临时修复处理
						if not t_task.activateTime then
							b_update = true
							t_task.activateTime = n_now
						end
						if not mis_condition.check_task(mis_data.t_mission, t_misData, n_labelId, n_taskId) then
							b_update = true
							delete_task(t_misData, n_labelId, n_taskId)
						end
					end
				end
			end
		end
		-- 刷新taskEvent
		-- 处理"因为配置下架而导致taskEvent无法自动刷新"的问题
		if t_misData.md5 ~= mis_data.t_mission.s_md5 then
			b_update = true
			if t_misData.taskEvent then
				for n_event, t_ in pairs(t_misData.taskEvent) do
					for s_key, _ in pairs(t_) do
						n_labelId, n_taskId = string_match(s_key, '(%d+)_(%d+)')
						n_labelId, n_taskId = tonumber(n_labelId), tonumber(n_taskId)
						if not t_conf.t_label[n_labelId] or not t_conf.t_label[n_labelId].t_task[n_taskId] then
							t_[s_key] = nil
						end
					end
					if not next(t_) then t_misData.taskEvent[n_event] = nil end
				end
				if not next(t_misData.taskEvent) then t_misData.taskEvent = nil end
			end
		end
	end

	-- 查询配置表,插入新增标签或任务
	for n_labelId, t_labelConf in pairs(t_conf.t_label) do
		if not t_misData.label or not t_misData.label[n_labelId] then
			-- 创建标签, 标签检查
			b_update = true
			t_misData.label = t_misData.label or {}
			n_ = mis_condition.check_label(t_labelConf)
			if n_ == t_labelStatus.n_ENABLE then
				t_label = {status = t_labelStatus.n_ENABLE, activateTime = n_now}
				t_misData.label[n_labelId] = t_label
				if t_labelConf.n_type == t_labelType.n_RANDOM then
					create_random_task(mis_data.t_mission, t_misData, n_labelId)
					t_label.random = 1
				else
					for n_taskId, t_taskConf in pairs(t_labelConf.t_task) do
						if mis_condition.check_task(mis_data.t_mission, nil, n_labelId, n_taskId) then
							create_task(mis_data.t_mission, t_misData, n_labelId, n_taskId)
						end
					end
				end
			elseif n_ == t_labelStatus.n_DISABLE then
				t_label = {status = t_labelStatus.n_DISABLE}
			elseif n_ == t_labelStatus.n_DEAD then
				t_label = {status = t_labelStatus.n_DEAD}
			end
			t_misData.label[n_labelId] = t_label
		else
			t_label = t_misData.label[n_labelId]
			if t_label.status == t_labelStatus.n_ENABLE then
				if t_labelConf.n_type == t_labelType.n_RANDOM then
					-- 如果当前没有可做任务，或者配置了完成次数限定并且还没达到限制时，生成一个随机任务
					if (not t_label.task or not mis_common.table_find(t_label.task, function(t_task) return not t_task.status end)) and (not t_labelConf.t_random.n_time or not t_label.finish or t_label.finish < t_labelConf.t_random.n_time) then
						b_update = true
						create_random_task(mis_data.t_mission, t_misData, n_labelId)
						t_label.random = t_label.random and t_label.random + 1 or 1
					end
				else
					for n_taskId, t_taskConf in pairs(t_labelConf.t_task) do
						if not t_label.task or not t_label.task[n_taskId] and mis_condition.check_task(mis_data.t_mission, nil, n_labelId, n_taskId) then
							b_update = true
							create_task(mis_data.t_mission, t_misData, n_labelId, n_taskId)
						end
					end
				end
			end
		end
	end
	if b_update then
		t_misData.loginTime = n_now
		t_misData.md5 = mis_data.t_mission.s_md5
		n_code, s_desc = t_user:set_mission_data(t_misData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	-- 响应
	if t_misData.label then
		for n_labelId, t_label in pairs(t_misData.label) do
			t_labelConf = t_conf.t_label[n_labelId]
			if t_label.status == t_labelStatus.n_ENABLE then
				t_ret.enable = t_ret.enable or {label = {}}
				t_ret.enable.label[n_labelId] = {activateTime = t_label.activateTime}
				-- ver 1.0
				for n_taskId, t_taskConf in pairs(t_labelConf.t_task) do
					if t_label.task and t_label.task[n_taskId] then
						t_task = t_label.task[n_taskId]
						if t_task.value or t_task.target or t_task.status or t_labelConf.n_type == t_labelType.n_RANDOM then
							if not t_ret.enable.label[n_labelId].task then t_ret.enable.label[n_labelId].task = {} end
							t_ret.enable.label[n_labelId].task[n_taskId] = {
								value = t_task.value;
								target = t_task.target;
								status = t_task.status;
								activateTime = t_task.activateTime;
								bonusId = t_task.bonusId;
							}
						end
					else
						if not t_ret.enable.label[n_labelId].task then t_ret.enable.label[n_labelId].task = {} end
						t_ret.enable.label[n_labelId].task[n_taskId] = {status = t_misStatus.n_PICKED}
					end
				end
				-- ver 2.0
				-- t_ret.enable.label[n_labelId].activateTime = t_label.activateTime
				-- if t_label.task then
				-- 	for n_taskId, t_task in pairs(t_label.task) do
				-- 		if t_task.value or t_task.target or t_task.status or t_labelConf.n_type == t_labelType.n_RANDOM then
				-- 			if not t_ret.enable.label[n_labelId].task then t_ret.enable.label[n_labelId].task = {} end
				-- 			t_ret.enable.label[n_labelId].task[n_taskId] = {
				-- 				value = t_task.value;
				-- 				target = t_task.target;
				-- 				status = t_task.status;
				-- 				activateTime = t_task.activateTime;
				-- 				bonusId = t_task.bonusId;
				-- 			}
				-- 		end
				-- 	end
				-- end
			elseif t_label.status == t_labelStatus.n_DISABLE or t_label.status == t_labelStatus.n_DEAD then
				t_ret.disable = t_ret.disable or {label = {}}
				t_ret.disable.label[n_labelId] = 1
			end
		end
	end
	return t_retCode.n_OK, t_ret
end

--------------------------------------------------------------
-- 说明：事件上报
-- 参数：event 				事件id
-- 		value 				增量
-- 返回：n					状态码
--		ts 					描述
this.mission_event = function()
	local t_params = ngx.ctx.t_params
	local _
	local b_update, n_daily, b_weekly
	local n_now, n_2, n_code, n_FINISH = ngx.time(), 0, 0, mis_config.t_missionEvent.n_FINISH
	local n_labelId, n_taskId, n_nextTime, n_, n_1, n_2, n_3
	local s_desc
	local t_user, t_misData, t_labelConf, t_taskConf, t_label, t_task, t_ret
	local t_eventConf, t_misStatus = mis_data.t_mission.t_eventConf, mis_config.t_missionStatus
	local t_func, t_finish, t_res = {}, {}, {}
	local f_2

	t_user = mis_data.get_user()
	n_code, t_misData = t_user:get_mission_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_misData
	end
	if t_misData.taskEvent and t_misData.taskEvent[t_params.event] then
		for s_key, _ in pairs(t_misData.taskEvent[t_params.event]) do
			n_labelId, n_taskId = string_match(s_key, '(%d+)_(%d+)')
			n_labelId, n_taskId = tonumber(n_labelId), tonumber(n_taskId)
			if not mis_data.t_mission.t_conf.t_label[n_labelId] then
				-- 标签配置已经不存在,删除数据
				b_update = true
				delete_label(t_misData, n_labelId)
			elseif not mis_data.t_mission.t_conf.t_label[n_labelId].t_task[n_taskId] then
				-- 任务配置已经不存在,删除数据
				b_update = true
				delete_task(t_misData, n_labelId, n_taskId)
			else
				t_labelConf = mis_data.t_mission.t_conf.t_label[n_labelId]
				t_taskConf = t_labelConf.t_task[n_taskId]
				t_label = t_misData.label[n_labelId]
				if not t_label.task then t_label.task = {} end
				t_task = t_label.task
				if not t_task[n_taskId] then t_task[n_taskId] = {} end
				t_task = t_task[n_taskId]
				if t_taskConf.n_daily and (not n_daily or t_taskConf.n_daily < n_daily) then n_daily = t_taskConf.n_daily end
				if t_taskConf.b_weekly then b_weekly = t_taskConf.b_weekly end
				-- hot fix: 外网bug临时修复处理
				if not t_task.activateTime then
					t_task.activateTime = n_now
					b_update = true
				end
				if t_labelConf.n_type == mis_config.t_labelType.n_RANDOM and t_labelConf.t_random.n_refreshTime and t_task.activateTime + t_labelConf.t_random.n_refreshTime <= n_now then
					-- 随机型任务带有超时刷新，并且这里已经超时
					n_nextTime = n_now + t_labelConf.t_random.n_refreshTime
				else
					if not t_task.value then t_task.value = 0 end
					if (not t_task.target and t_task.status) or (t_task.target and t_taskConf.tn_target[#t_taskConf.tn_target] <= t_task.value) then
						-- 任务已经完成，重复上报
						if not t_ret then t_ret = {} end
						if not t_ret[n_labelId] then t_ret[n_labelId] = {task = {}} end
						t_ret[n_labelId].task[n_taskId] = {status = t_task.status}
					else
						b_update = true
						if t_task.target then n_ = t_task.value end
						t_task.value = t_task.value and t_task.value + t_params.value or t_params.value
						t_task.value = t_task.target and math_min(t_task.value, t_taskConf.tn_target[#t_taskConf.tn_target]) or math_min(t_task.value, t_taskConf.tn_target)
						if not t_ret then t_ret = {} end
						if not t_ret[n_labelId] then t_ret[n_labelId] = {task = {}} end
						t_ret[n_labelId].task[n_taskId] = {value = t_task.value}
						if (t_task.target or t_taskConf.tn_target) <= t_task.value then
							-- 任务完成
							mis_log.remote_pure_day('mission', mis_common.table_to_json({
								key = 'complete';
								ip = t_params.s_remoteAddr;
								uin = t_params.uin;
								time = n_now;
								country = t_params.country;
								apiid = t_params.apiid;
								ver = t_params.ver;
								lang = t_params.lang;
								labelId = n_labelId;
								taskId = n_taskId;
								bonusId = 'null';
							}))
							t_label.done = t_label.done and t_label.done + 1 or 1
							-- 关闭事件通知
							if not n_daily and not t_taskConf.b_weekly and (not t_task.target or t_taskConf.tn_target[#t_taskConf.tn_target] <= t_task.value) then
								t_misData.taskEvent[t_params.event][s_key] = nil
								if not next(t_misData.taskEvent[t_params.event]) then
									t_misData.taskEvent[t_params.event] = nil
								end
							end
							-- 计算跨度
							if t_task.target then
								for n_i, n_target in ipairs(t_taskConf.tn_target) do
									if n_ <= n_target then
										n_ = n_i - (n_ == n_target and 0 or 1)
										break
									end
								end
								for n_i = #t_taskConf.tn_target, 1, -1 do
									n_2 = t_taskConf.tn_target[n_i]
									if n_2 <= t_task.value then
										n_2 = n_i
										break
									end
								end
								t_finish[n_labelId] = t_finish[n_labelId] and t_finish[n_labelId] + (n_2 - n_) or (n_2 - n_)
							else
								-- 普通任务的跨度始终为1
								t_finish[n_labelId] = t_finish[n_labelId] and t_finish[n_labelId] + 1 or 1
							end
							if t_labelConf.b_auto then
								-- 自动领取
								n_code, s_desc, _, f_2 = mission_finish_core(t_misData, n_labelId, n_taskId)
								if n_code ~= t_retCode.n_OK then
									return n_code, s_desc
								end
								t_ret[n_labelId].task[n_taskId].status = t_misStatus.n_PICKED
								t_func[#t_func+1] = f_2
							else
								t_task.status = t_misStatus.n_DONE
								t_ret[n_labelId].task[n_taskId].status = t_task.status
							end
						end
					end
				end
			end
		end
	end
	-- 推进自动类型任务
	if #t_finish > 0 and t_misData.taskEvent and t_misData.taskEvent[n_FINISH] then
		for s_key, t_ in pairs(t_misData.taskEvent[n_FINISH]) do
			n_labelId, n_taskId = string_match(s_key, '(%d+)_(%d+)')
			n_labelId, n_taskId = tonumber(n_labelId), tonumber(n_taskId)
			if t_finish[n_labelId] then
				t_labelConf = mis_data.t_mission.t_conf.t_label[n_labelId]
				t_taskConf = t_labelConf.t_task[n_taskId]
				if not t_misData.label[n_labelId] then t_misData.label[n_labelId] = {} end
				t_label = t_misData.label[n_labelId]
				if not t_label.task then t_label.task = {} end
				t_task = t_label.task
				if not t_task[n_taskId] then t_task[n_taskId] = {} end
				t_task = t_label.task[n_taskId]
				if not t_task.status then
					t_task.value = t_task.value and t_task.value + t_finish[n_labelId] or t_finish[n_labelId]
					t_task.value = t_task.target and math_min(t_task.value, t_taskConf.tn_target[#t_taskConf.tn_target]) or math_min(t_task.value, t_taskConf.tn_target)
					if not t_ret[n_labelId] then t_ret[n_labelId] = {task = {}} end
					t_ret[n_labelId].task[n_taskId] = {value = t_task.value}
					if (not t_task.target and t_taskConf.tn_target <= t_task.value) or (t_task.target and t_task.target <= t_task.value) then
						-- 任务完成
						mis_log.remote_pure_day('mission', mis_common.table_to_json({
							key = 'complete';
							ip = t_params.s_remoteAddr;
							uin = t_params.uin;
							time = n_now;
							country = t_params.country;
							apiid = t_params.apiid;
							ver = t_params.ver;
							lang = t_params.lang;
							labelId = n_labelId;
							taskId = n_taskId;
							bonusId = 'null';
						}))
						t_label.done = t_label.done and t_label.done + 1 or 1
						if not t_task.target or t_taskConf.tn_target[#t_taskConf.tn_target] <= t_task.value then
							t_misData.taskEvent[n_FINISH][s_key] = nil
							if not next(t_misData.taskEvent[n_FINISH]) then
								t_misData.taskEvent[n_FINISH] = nil
							end
						end
						if t_labelConf.b_auto then
							-- 自动领取
							n_code, s_desc, _, f_2 = mission_finish_core(t_misData, n_labelId, n_taskId)
							if n_code ~= t_retCode.n_OK then
								return n_code, s_desc
							end
							t_ret[n_labelId].task[n_taskId].status = t_misStatus.n_PICKED
							t_func[#t_func+1] = f_2
						else
							t_task.status = t_misStatus.n_DONE
							t_ret[n_labelId].task[n_taskId].status = t_task.status
						end
					end
				end
			end
		end
	end

	if b_update then
		n_code, s_desc = t_user:set_mission_data(t_misData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end
	if #t_func > 0 then
		for _, f_ in pairs(t_func) do
			n_code, s_desc = f_()
			if n_code ~= t_retCode.n_OK then
				return n_code, s_desc
			end
		end
	end
	-- 如果没有任务推进，禁止客户端上报
	-- ver 1.0
	if not b_update then
		if n_daily or b_weekly or n_nextTime then
			n_1 = n_daily and n_now + mis_common.time_to_time(n_daily, n_now) or math_huge
			n_2 = b_weekly and n_now + mis_common.time_to_next_week() or math_huge
			n_3 = n_nextTime or math_huge
			t_res.nextTime = math_min(n_1, math_min(n_2, n_3))
		else
			t_res.nextTime = -1
		end
	end
	t_res.label = t_ret
	-- ver 2.0
	-- nextTime和t_ret互斥存在
	return t_retCode.n_OK, t_res
end

--------------------------------------------------------------
-- 说明：领取任务奖励
-- 参数：labelId				标签id
--		taskId 				任务id
--		bonusId 			奖励id
-- 返回：n					状态码
--		ts 					描述
this.mission_finish = function()
	local t_params = ngx.ctx.t_params
	local n_code
	local s_desc, s_items
	local t_user, t_misData, t_label, t_task, t_done
	local f_1, f_2

	t_user = mis_data.get_user()
	n_code, t_misData = t_user:get_mission_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_misData
	end
	if not t_misData.label or not t_misData.label[t_params.labelId] then
		return t_retCode.n_OPER_ERR, 'label not activate'
	end
	t_label = t_misData.label[t_params.labelId]
	if not t_label.task or not t_label.task[t_params.taskId] then
		return t_retCode.n_OPER_ERR, "task isn't done"
	end
	t_task = t_label.task[t_params.taskId]
	if t_task.status ~= mis_config.t_missionStatus.n_DONE then
		return t_retCode.n_OPER_ERR, "task isn't done"
	end

	n_code, s_desc, f_1, f_2 = mission_finish_core(t_misData, t_params.labelId, t_params.taskId, t_params.bonusId)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	n_code, s_desc = f_1()
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	n_code, s_desc = f_2()
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	if t_task.target and t_task.status == mis_config.t_missionStatus.n_DONE then
		t_done = {[t_params.labelId..'_'..t_params.taskId] = {
			value = t_task.value;
			target = t_task.target;
			status = t_task.status;
		}}
	end

	return t_retCode.n_OK, t_done and {done = t_done} or nil
end

--------------------------------------------------------------
-- 说明：奥特曼活动数据上报
-- 参数：id 					地图id
--		rank				排名
this.outman_upload = function()
	local t_params = ngx.ctx.t_params
	local t_user = mis_data.get_user()
	local n_code, t_outmanData = t_user:get_outman_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_outmanData
	end
	local n_now = ngx.time()
	if not t_outmanData[t_params.id] or t_outmanData[t_params.id].time + 640 <= n_now then
		t_outmanData[t_params.id] = t_outmanData[t_params.id] or {}
		t_outmanData[t_params.id].time = n_now
		t_outmanData[t_params.id].rank = t_params.rank
		local n_code, s_desc = t_user:set_outman_data(t_outmanData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		local s_ = t_params.uin .. '|' .. t_params.id
		if t_params.rank then
			s_ = s_ .. '|' .. t_params.rank
		end
		mis_log.day('outman', s_)
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：测试接口
this.back_test = function()
	local t_params = ngx.ctx.t_params
	local t_user = mis_data.get_user()
	local n_code, t_backData = t_user:get_back_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_backData
	end
	if t_params.reset then
		t_user:new_back_data(t_backData)
	end
	if t_params.status then
		t_backData.status = t_params.status
	end
	if t_params.loginTime then
		t_backData.loginTime = t_params.loginTime
	end
	if t_params.startTime then
		t_backData.startTime = t_params.startTime
	end
	local n_code, s_desc = t_user:set_back_data(t_backData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	return t_retCode.n_OK
end


--------------------------------------------------------------
-- 说明：计算当前时间是否在生日前后一周范围
-- 参数：n_birthday
-- 返回：b
local function is_range_week_time (n_birthday, n_nowtime, n_pretime, n_aftertime)
	if n_birthday and n_birthday > 0 then
		local tb = {}
		tb.year = os.date("%Y", n_nowtime)
		tb.month = math.floor(n_birthday / 100)
		tb.day = n_birthday % 100

		tb.unixtime =  os.time({year = tb.year, month = tb.month, day = tb.day, hour = 0, min = 0, sec = 0})
		tb.unixtime = tonumber(tb.unixtime)

		local n_lastweek_unixtime = tb.unixtime - n_pretime * 86400
		local n_nextweek_unixtime = tb.unixtime + (n_aftertime + 1) * 86400

		if n_nowtime > n_lastweek_unixtime and n_nowtime < n_nextweek_unixtime then
			return true
		end
	end
	return false
end

--------------------------------------------------------------
-- 说明：birthday 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_birthday = function()
	if mis_data.t_birthday.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'birthday disable'
	end

	local t_params  		= ngx.ctx.t_params
	local t_birthdayConf 	= mis_data.t_birthday.t_conf

	-- 活动有效期间
	local n_nowtime 	= mis_data.get_server_time()
	local n_valid 		= t_birthdayConf.onshow or 0
	local n_start_time 	= mis_common.date_to_unix(t_birthdayConf.start_time)
	local n_end_time   	= mis_common.date_to_unix(t_birthdayConf.end_time)
	if n_nowtime < n_start_time or n_nowtime > n_end_time or n_valid ~= 1 then
		return t_retCode.n_OPER_ERR, 'invalid activity'
	end

	-- 渠道控制
	if t_birthdayConf.apiids then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)
		local t_apiids = mis_uu.split(t_birthdayConf.apiids, ',')
		for _, v in pairs(t_apiids) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if not b_valid_apiid then
			return t_retCode.n_OPER_ERR, 'apiid is invalid'
		end
	end

	-- 版本号控制
	if t_birthdayConf.version_min then
		local n_l = mis_common.version_to_number(t_params.ver or 0)
		local n_r = mis_common.version_to_number(t_birthdayConf.version_min or 0)
		if n_l < n_r then
			return t_retCode.n_OPER_ERR, 'version too low'
		end
	end

	return t_retCode.n_OK
end

--计算生日倒计时
local function calc_left_birthday(n_nowtime, birthday)
	if not n_nowtime or not birthday then 
		return
	end

	local ret = {}
	local now_year = os.date("%Y", n_nowtime)
	local now_month = os.date("%m", n_nowtime)
	local now_day = os.date("%d", n_nowtime)
	--剩余时间计算
	local birthday_month = math.floor(birthday/100)
	local birthday_day = birthday%100
	local birthday_ts = os.time({year=now_year, month=birthday_month, day=birthday_day, hour=0, min=0, sec=0})
	if birthday > (now_month*100+now_day) then 
		local leaving_time_ts = birthday_ts - n_nowtime
		ret.leaving_time_day = math.floor(leaving_time_ts / 86400)
		--ret.leaving_time_hour = math.floor( (leaving_time_ts - ret.leaving_time_day*86400) / 3600)
		--ret.leaving_time_min = math.floor( (leaving_time_ts - ret.leaving_time_day*86400 - ret.leaving_time_hour*3600) / 60)
		--ret.leaving_time_sec = math.floor( leaving_time_ts - ret.leaving_time_day*86400 - ret.leaving_time_hour*3600 - ret.leaving_time_min*60 ) 
		--只展示天数，所以+1
		ret.leaving_time_day = ret.leaving_time_day + 1
	elseif birthday < (now_month*100+now_day) then
		birthday_ts = os.time({year=now_year + 1, month=birthday_month, day=birthday_day, hour=0, min=0, sec=0})
		local leaving_time_ts = birthday_ts - n_nowtime 
		ret.leaving_time_day = math.floor(leaving_time_ts / 86400) + 1
	elseif birthday == now_month*100+now_day then 
		ret.leaving_time_day = 0
	end
	ret.birthday_ts = birthday_ts

	return ret
end

--------------------------------------------------------------
-- 说明：获取玩家生日数据
-- 返回：n					状态码
--		ts 					描述
this.get_birthday_info = function()
	local t_params = ngx.ctx.t_params
	local n_code, s_desc, t_user, t_userbirthday, t_share
	local t_birthdayConf 	= mis_data.t_birthday.t_conf
	local n_nowtime 		= mis_data.get_server_time()

	-- 获取生日礼包数据
	-- mis_log.debug("get_birthday_info:" .. mis_common.table_to_json(t_birthdayConf))

	t_user = mis_data.get_user()
	n_code, t_userbirthday = t_user:get_birthday_data(true)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user birthday info error'
	end

	-- 即将第几次生日
	local b_update  = false
	local n_finish  = t_userbirthday.finish
	if t_userbirthday.gift and n_finish == #t_userbirthday.gift then
		if not t_userbirthday.gift[n_finish] then
			mis_log.day('birthday_error', 'get_birthday_info|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' ..
					t_params.country .. '|' .. t_params.lang .. '|' .. n_finish)
			return t_retCode.n_SYS_ERR, 'gift list is empty'
		end

		--更新玩家生日
		if not t_userbirthday.gift[n_finish].ctime then
			-- 第 n_finish 生日还未领取奖励
		else
			local n_finishtime 	= t_userbirthday.gift[n_finish].ctime
			if n_nowtime > n_finishtime + 300 * 86400 then
				n_finish = n_finish + 1
				t_userbirthday.finish 					= n_finish
				t_userbirthday.gift 					= t_userbirthday.gift or {}
				t_userbirthday.gift[n_finish] 			= t_userbirthday.gift[n_finish] or {}
				t_userbirthday.share_cake               = t_userbirthday.share_cake or {}
				t_userbirthday.share_cake[n_finish]		= t_userbirthday.share_cake[n_finish] or {}
				t_userbirthday.share_cake[n_finish].num	= t_birthdayConf.cake.num or 10
				t_userbirthday.share_cake[n_finish].cake_friend = t_userbirthday.share_cake[n_finish].cake_friend or {}

				b_update = true
			end
		end

		--重置赠送蛋糕份额
		t_userbirthday.share_cake  = t_userbirthday.share_cake or {}
		t_share 				   = t_userbirthday.share_cake[n_finish]
		if t_share and t_share.updatetime then
			if n_nowtime > t_share.updatetime + 300 * 86400 then
				t_share.updatetime 						= nil
				t_userbirthday.share_cake[n_finish]		= {}
				t_userbirthday.share_cake[n_finish].num	= 10
				t_userbirthday.share_cake[n_finish].cake_friend = {}

				b_update = true
			end
		end
		if b_update then
			mis_log.day('birthday_opt', 'update_ok  |' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' ..
					t_params.country .. '|' .. t_params.lang .. '|' .. '|' .. n_finish .. mis_common.table_to_json(t_userbirthday.gift))

			n_code, s_desc = t_user:set_birthday_data(t_userbirthday)
			if n_code ~= t_retCode.n_OK then
				return n_code, s_desc
			end
		end
	end

	--计算生日倒计时
	local ret = calc_left_birthday(n_nowtime, t_userbirthday.birthday)
	if ret then 
		for k, v in pairs(ret) do
			t_userbirthday[k] = v
		end
	end

	return t_retCode.n_OK, {servertime = n_nowtime, data = t_userbirthday}
end

--------------------------------------------------------------
-- 说明：参加生日派对
-- 参数：month					月份
--		day 					日期
--		itemID					四季装扮
--		num						道具数量（0表示已拥有该装扮，不再赠送）
-- 返回：n					状态码
--		ts 					描述
this.join_birthday_party = function()
	local t_params  = ngx.ctx.t_params
	local n_month 	= t_params.month or 0
	local n_day 	= t_params.day or 0
	local n_itemID 	= t_params.itemID or 0
	local n_num		= t_params.num or 0
	local n_code, s_desc, s_items
	local t_user, t_userbirthday
	local t_birthdayConf = mis_data.t_birthday.t_conf
	local n_nowtime = mis_data.get_server_time()
	
	if n_month <= 0 or n_month > 12 or n_day <= 0 or n_day > 31 or not n_itemID then
		mis_log.day('birthday_error', 'join_birthday_party|' .. t_params.uin .. '|' .. n_month .. '|' .. n_day .. '|' .. (n_itemID or "nil") .. "| param error1")
		return t_retCode.n_PARAM_ERR, 'param error'
	end

	-- 星座检验
	local s_constellation
	local n_birthday = n_month * 100 + n_day
	for k, v in pairs(t_birthdayConf.constellation) do
		if (n_birthday >= v[1].stime and n_birthday <= v[1].etime) or (n_birthday >= v[2].stime and n_birthday <= v[2].etime) then
			s_constellation = v.name
			break
		end
	end
	if not s_constellation then
		mis_log.day('birthday_error', 'join_birthday_party|' .. t_params.uin .. '|' .. n_month .. '|' .. n_day .. '|' .. n_itemID .. "| constellation error")
		return t_retCode.n_PARAM_ERR, 'constellation error'
	end

	t_user = mis_data.get_user()
	n_code, t_userbirthday = t_user:get_birthday_data()
	if n_code ~= t_retCode.n_OK then
		mis_log.day('birthday_error', 'join_birthday_party|' .. t_params.uin .. '|' .. n_month .. '|' .. n_day .. '|' .. n_itemID .. '|'.. n_code .."| get_birthday_data error")
		return n_code, t_userbirthday
	end

	-- 检验已参加派对
	if t_userbirthday.birthday then
		mis_log.day('birthday_error', 'join_birthday_party|' .. t_params.uin .. '|' .. t_userbirthday.birthday .. '|' .. 'already at the party')
		return t_retCode.n_OPER_ERR, 'already at the party'
	end

	-- 奖励配置校验
	local b_exist = false
	if t_birthdayConf.show_skin then
		for _, v in pairs(t_birthdayConf.show_skin) do
			if v.itemID and v.itemID == n_itemID then
				b_exist = true
				break
			end
		end
	end

	if b_exist and n_num == 1 then
		local t_gift = {{id = n_itemID, num = n_num}}
		n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_gift, mis_config.t_workType.s_BIRTHDAY, 'join_birthday_party')
		if n_code ~= t_retCode.n_OK then
			mis_log.day('birthday_error', 'join_birthday_party|' .. t_params.uin .. '|' .. s_items .. '|'.. n_code .. " | add_items error")
			return n_code, s_desc
		end
	end

	-- 参数入库
	local n_finish 					= 1
	t_userbirthday.birthday 		= n_birthday
	t_userbirthday.constellation 	= s_constellation
	t_userbirthday.gift 			= {}
	t_userbirthday.attire 			= n_itemID
	t_userbirthday.jointime 		= n_nowtime
	t_userbirthday.finish 			= n_finish
	t_userbirthday.gift[n_finish] 	= {}
	t_userbirthday.share_cake		= {}
	t_userbirthday.share_cake[n_finish]		= {}
	t_userbirthday.share_cake[n_finish].num	= 10
	t_userbirthday.share_cake[n_finish].cake_friend = {}
	
	n_code, s_desc = t_user:set_birthday_data(t_userbirthday)
	if n_code ~= t_retCode.n_OK then
		mis_log.day('birthday_error', 'join_birthday_party|' .. t_params.uin .. '|' .. n_month .. '|' .. n_day .. '|' .. n_itemID .. '|'.. n_code ..  "| set_birthday_data error")
		return n_code, s_desc
	end

	mis_log.remote_day('birthday', mis_common.table_to_json({
		uin = t_params.uin;
		birthday_game = t_userbirthday.birthday;
		reward_way = 0;									-- 0：生日祝福派对邀请 1：生日祝福
		op_type = 0;									-- 0：正常下发 1：补发 2：其他
		bonus = {prop_id = n_itemID, prop_num = 1};
		channel = t_params.apiid or 'null';
		version = t_params.ver or 'null';
		country = t_params.country or 'null';
		language = t_params.lang or 'null';
		ts = ngx.time();
		dt = mis_common.get_beijing_date();
		ip = t_params.s_remoteAddr;
	}))

	--计算生日倒计时
	local ret = calc_left_birthday(n_nowtime, t_userbirthday.birthday)
	if ret then 
		for k, v in pairs(ret) do
			t_userbirthday[k] = v
		end
	end

	return t_retCode.n_OK, {servertime = n_nowtime, data = t_userbirthday}
end

--------------------------------------------------------------
-- 说明：领取生日当天礼物
-- 参数: headID					星座头像
--       itemID					奖励
--  	 num					份额

-- 返回：n					状态码
--		ts 					描述
this.collect_birthday_gift = function()
	local t_params = ngx.ctx.t_params
	local t_gift, t_record = {}, {}
	local n_loop = 1
	local n_code, s_desc, s_items
	local t_user, t_userbirthday
	local t_birthdayConf = mis_data.t_birthday.t_conf
	local n_nowtime = mis_data.get_server_time()
	local n_stime = t_birthdayConf.duration.stime
	local n_etime = t_birthdayConf.duration.etime

	-- 解析礼物
	while (true)
	do
		local s_item = 'itemID' .. n_loop
		local s_num = 'num' .. n_loop
		if not mis_common.exist_table_key(t_params, s_item) or not mis_common.exist_table_key(t_params, s_num) then
			break
		end

		n_loop = n_loop + 1
		table_insert(t_gift, {id = tonumber(t_params[s_item]), num = tonumber(t_params[s_num])})
		table_insert(t_record, {prop_id = tonumber(t_params[s_item]), prop_num = tonumber(t_params[s_num])})
	end

	t_user = mis_data.get_user()
	n_code, t_userbirthday = t_user:get_birthday_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_userbirthday
	end

	-- 校验是否在生日活动范围
	if is_range_week_time(t_userbirthday.birthday, n_nowtime, n_stime, n_etime) == false then
		return t_retCode.n_OPER_ERR, {reason = 'not between in the birthday time', stime = n_nowtime}
	end

	local n_finish = t_userbirthday.finish
	t_userbirthday.gift = t_userbirthday.gift or {}
	t_userbirthday.gift[n_finish] = t_userbirthday.gift[n_finish] or {}

	if not t_userbirthday.gift[n_finish] or not t_birthdayConf.gift then
		mis_log.day('birthday_error', 'collect gift|' .. t_params.uin .. '|' .. n_finish .. '|' .. 'not exist')
		return t_retCode.n_SYS_ERR, 'gift error'
	end

	-- 校验是否已领取奖励
	if t_userbirthday.gift[n_finish].ctime then
		mis_log.day('birthday_error', 'collect info|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' ..
				t_params.country .. '|' .. t_params.lang .. '|' .. n_finish .. 'already collect birthday gift')
		return t_retCode.n_OPER_ERR, '已领取奖励'
	end
	if n_finish ~= #t_userbirthday.gift then
		mis_log.day('birthday_error', 'collect info|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' ..
				t_params.country .. '|' .. t_params.lang .. '|' .. n_finish .. mis_common.table_to_json(t_userbirthday.gift))
		return t_retCode.n_SYS_ERR, 'gift lenght error'
	end

	-- 待领取的奖励是否和配置参数一致
	local n_index 		= math_min(n_finish, #t_birthdayConf.gift)
	local t_giftconf 	= t_birthdayConf.gift[n_index] or {}

	for _, v1 in pairs(t_gift) do
		local b_exit = false
		for _, v2 in pairs(t_giftconf) do
			if mis_common.table_find(v2, v1.id) then
				b_exit = true
				break
			end
		end
		if b_exit == false then
			mis_log.day('birthday_error', 'collect info|' .. t_params.uin .. '|' .. t_params.ver .. '|' .. t_params.apiid .. '|' ..
					t_params.country .. '|' .. t_params.lang  .. '|' .. n_finish .. '|' .. n_index .. '|' .. mis_common.table_to_json(t_giftconf))
			return t_retCode.n_SYS_ERR, 'gift conf error'
		end
	end

	-- 发放奖励
	n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_gift, mis_config.t_workType.s_BIRTHDAY, 'collect_birthday_gift')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('birthday_error', 'collect gift|' .. t_params.uin .. '|' .. s_items)
		return n_code, s_desc
	end

	t_gift.ctime 					= n_nowtime
	t_userbirthday.gift[n_finish] 	= t_gift

	n_code, s_desc = t_user:set_birthday_data(t_userbirthday)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	mis_log.remote_day('birthday', mis_common.table_to_json({
		uin = t_params.uin;
		birthday_game = t_userbirthday.birthday;
		reward_way = 1;									-- 0：生日祝福派对邀请 1：生日祝福
		op_type = 0;									-- 0：正常下发 1：补发 2：其他
		bonus = t_record;
		channel = t_params.apiid or 'null';
		version = t_params.ver or 'null';
		country = t_params.country or 'null';
		language = t_params.lang or 'null';
		ts = ngx.time();
		dt = mis_common.get_beijing_date();
		ip = t_params.s_remoteAddr;
	}))

	return t_retCode.n_OK, t_gift
end

--------------------------------------------------------------
-- 说明：分享生日蛋糕
-- 参数：fri_uin			好友迷你号
--		num					蛋糕数量
-- 返回：n					状态码
--		ts 					描述
this.share_birthday_cake = function()
	local t_params = ngx.ctx.t_params
	local n_fri_uin = t_params.fri_uin or 0
	local n_num = t_params.num or 0
	local t_birthdayConf = mis_data.t_birthday.t_conf
	local n_code, ts_desc, t_user, t_userbirthday
	local n_finish, n_remain_count
	local n_nowtime = mis_data.get_server_time()
	local n_stime = t_birthdayConf.duration.stime
	local n_etime = t_birthdayConf.duration.etime

	-- 数目校验
	if n_num <= 0 then
		ts_desc = 'num less than 0'
		mis_log.day('birthday_error', 'share_cake|' .. t_params.uin .. '|' .. ts_desc)
		return t_retCode.n_PARAM_ERR, ts_desc
	end
	if t_birthdayConf.cake and not t_birthdayConf.cake.itemID then
		ts_desc = 'cake conf not exist'
		mis_log.day('birthday_error', 'share_cake|' .. t_params.uin .. '|' .. ts_desc)
		return t_retCode.n_PARAM_ERR, ts_desc
	end

	t_user = mis_data.get_user()
	n_code, t_userbirthday = t_user:get_birthday_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_userbirthday
	end
	-- 校验是否在生日活动范围
	if is_range_week_time(t_userbirthday.birthday, n_nowtime, n_stime, n_etime) == false then
		return t_retCode.n_OPER_ERR, 'not between in the birthday time'
	end

	n_finish = t_userbirthday.finish
	t_userbirthday.share_cake = t_userbirthday.share_cake or {}
	n_remain_count = t_userbirthday.share_cake[n_finish] and t_userbirthday.share_cake[n_finish].num or 0

	if n_num > n_remain_count or n_remain_count == 0 then
		ts_desc = '生日蛋糕已经分完啦~小伙伴们都收到蛋糕了！'
		mis_log.day('birthday_error', 'share_cake|' .. t_params.uin .. '|' .. ts_desc)
		return t_retCode.n_PARAM_ERR, ts_desc
	end

	-- 是否好友
	n_code, ts_desc = mis_bridge.friend_has_relation(t_params.uin, n_fri_uin,3)
	if n_code ~= t_retCode.n_OK then
		-- 非好友未实名用户，校验是否已有其他赠送
		if t_user:auth_user_cake_status(n_fri_uin) then
			ts_desc = '该好友当日已经收到蛋糕祝福，请赠送给其他好友!'
			mis_log.day('birthday_error', 'share_cake|' .. t_params.uin .. '|' .. ts_desc .. '|' .. n_fri_uin)
			return t_retCode.n_OPER_ERR, ts_desc
		end
		if t_user:is_exist_unauth_user(n_fri_uin) then
			if t_user:set_user_cake_status(n_fri_uin)  ~= t_retCode.n_OK then
				ts_desc = 'share error' .. n_code
				mis_log.day('birthday_error', 'share_cake|status|' .. t_params.uin .. '|' .. ts_desc .. '|' .. n_fri_uin)
				return t_retCode.n_OPER_ERR, ts_desc
			end
		end
		if t_user:insert_user_cake_backup_status(n_fri_uin, 1) ~= t_retCode.n_OK then
			mis_log.day('birthday_error', 'share_cake|add items|' .. t_params.uin .. '|' .. n_fri_uin)
			return n_code, 'share_cake add items failed'
		end
	end
	-- 是否已赠送
	t_userbirthday.share_cake[n_finish]				= t_userbirthday.share_cake[n_finish] or {}
	t_userbirthday.share_cake[n_finish].updatetime  = n_nowtime
	t_userbirthday.share_cake[n_finish].cake_friend = t_userbirthday.share_cake[n_finish].cake_friend or {}

	for _, v in pairs(t_userbirthday.share_cake[n_finish].cake_friend) do
		if v == n_fri_uin then
			ts_desc = '该好友当日已经收到蛋糕祝福，请赠送给其他好友!'
			mis_log.day('birthday_error', 'share_cake|' .. t_params.uin .. '|' .. ts_desc .. '|' .. n_fri_uin)
			return t_retCode.n_PARAM_ERR, ts_desc
		end
	end

	-- 赠送邮件
	local s_title = '好友的生日蛋糕'
	local s_body = '给你赠送了生日蛋糕，不要忘记送上你热情的祝福噢!你也想拥有属于你的生日祝福？！那就快完成实名认证并填写生日信息吧！'
	local t_items = {{id = t_birthdayConf.cake.itemID, num = n_num}}
	n_code, ts_desc = mis_bridge.send_email(n_fri_uin, s_title, "您的好友"..t_params.uin .. s_body, 32503651200, t_items, 0)
	if n_code ~= t_retCode.n_OK then
		mis_log.day('birthday_error', 'share_cake|' .. t_params.uin .. '|' .. ts_desc .. '|' .. n_fri_uin)
		return n_code, ts_desc
	end

	t_userbirthday.share_cake[n_finish].num 	= t_userbirthday.share_cake[n_finish].num - n_num
	table_insert(t_userbirthday.share_cake[n_finish].cake_friend, n_fri_uin)

	n_code, ts_desc = t_user:set_birthday_data(t_userbirthday)
	if n_code ~= t_retCode.n_OK then
		return n_code, ts_desc
	end

	mis_log.remote_day('birthday', mis_common.table_to_json({
		uin = t_params.uin;
		friend_uin = n_fri_uin;
		birthday_game = t_userbirthday.birthday;
		reward_way = 1;									-- 0：生日祝福派对邀请 1：生日祝福
		op_type = 0;									-- 0：正常下发 1：补发 2：其他
		bonus = {prop_id = t_birthdayConf.cake.itemID, prop_num = n_num};
		channel = t_params.apiid or 'null';
		version = t_params.ver or 'null';
		country = t_params.country or 'null';
		language = t_params.lang or 'null';
		ts = ngx.time();
		dt = mis_common.get_beijing_date();
		ip = t_params.s_remoteAddr;
	}))

	return t_retCode.n_OK,  {cakecount = t_userbirthday.share_cake[n_finish].num, cakefriend = t_userbirthday.share_cake[n_finish].cake_friend}
end

--------------------------------------------------------------
-- 说明：获取好友列表 （好友不满15人，未实名新增用户凑数）
-- 返回：n					状态码
--		ts 					描述
this.get_friend_list = function()
	local t_params = ngx.ctx.t_params
	local n_noreal = tonumber(t_params.noreal or 0)
	local n_code, ts_desc, t_user, t_userbirthday
	local t_unauth_users, t_all_users = {}, {}
	local n_friend_count, t_friend_list = 0, {}
	local t_birthdayConf = mis_data.t_birthday.t_conf
	local n_unauth_count = t_birthdayConf.unauth_count

	n_code, t_friend_list = mis_bridge.query_friend_list(t_params.uin)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'query friend list failed!'
	end

	-- 玩家好友列表人数不满15人，则从未实名的用户中抽取
	if not mis_common.tableIsEmpty(t_friend_list) then
		n_friend_count =  #t_friend_list
	else
		n_friend_count = 0
	end
	if n_friend_count < 15 and n_noreal == 1 then
		t_user = mis_data.get_user()
		n_code, t_userbirthday = t_user:get_birthday_data(true)
		if n_code ~= t_retCode.n_OK then
			return n_code, t_userbirthday
		end

		--名称未变，但是功能实际根据策划需求已修改为获取未实名+实名的所有玩家了
		n_code, t_unauth_users = t_user:get_unauth_data(n_unauth_count)
		if n_code ~= t_retCode.n_OK then
			t_unauth_users = {}
		end
		-- mis_log.debug('unauth:' .. n_code .. mis_common.table_to_json(t_unauth_users))
	end

	-- 好友、非好友
	for _, v in pairs(t_friend_list) do
		if v['uin'] and v['relation'] then
			local value_shift = lshift(1, 3)					--0:申请 1:被申请 2:单向好友 3:双向好友
			local value_bitand = band(v['relation'], value_shift)
			if value_bitand > 0 then table_insert(t_all_users, tonumber(v['uin'])) end
		end
	end
	for _, v in pairs(t_unauth_users) do
		if v['uin'] then table_insert(t_all_users, tonumber(v['uin'])) end
	end

	return t_retCode.n_OK, {count = n_friend_count, friendlist = t_all_users}
end

--------------------------------------------------------------
-- 说明：rotate业务前置检测
-- 参数：createTime			注册时间
-- 返回：n					状态码
--		ts 					描述
this.pre_rotate = function()
	local t_params = ngx.ctx.t_params
	local n_now = ngx.time()
	local t_ = mis_data.t_rotate
	if t_.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'rotate disable'
	end
	if t_.t_conf.n_startTime and n_now < t_.t_conf.n_startTime then
		return t_retCode.n_OPER_ERR, 'rotate out of time'
	end
	if t_.t_conf.n_closeTime and t_params.act == 'rotate' and t_.t_conf.n_closeTime < n_now then
		return t_retCode.n_OPER_ERR, 'rotate out of time'
	end
	local n_code, s_desc = this.pre_mission()
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：拉取转盘状态
-- 返回：n					状态码
--		ts 					描述
this.rotate_status = function()
	local t_params = ngx.ctx.t_params
	local n_now, n_code, n_activateTime, n_refreshTime, n_daily = ngx.time()
	local s_desc
	local s_coin = mis_config.t_specialItem.s_ROTATE
	local t_spData, t_misData, t_rotateData, t_ret, t_labelConf
	local t_user = mis_data.get_user()

	n_code, t_spData = t_user:get_specialItem_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_spData
	end
	n_code, t_misData = this.mission_status()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_misData
	end
	n_code, t_rotateData = t_user:get_rotate_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_rotateData
	end

	if not t_rotateData.activateTime then
		-- 首次免费
		t_spData[s_coin] = t_spData[s_coin] and t_spData[s_coin] + 1 or 1
		n_code, s_desc = t_user:set_specialItem_data(t_spData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
		t_rotateData.activateTime = ngx.time()
		n_code, s_desc = t_user:set_rotate_data(t_rotateData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	if t_misData.enable and t_misData.enable.label then
		for n_labelId, t_ in pairs(t_misData.enable.label) do
			t_labelConf = mis_data.t_mission.t_conf.t_label[n_labelId]
			if t_labelConf.n_type == mis_config.t_labelType.n_RANDOM then
				n_daily = t_labelConf.t_random.n_daily
				if t_.task then
					for _, t_2 in pairs(t_.task) do
						if not t_2.status and t_2.activateTime then
							n_activateTime = t_2.activateTime
							n_refreshTime = t_labelConf.t_random.n_refreshTime
							break
						end
					end
				end
			end
			if n_activateTime then break end
		end
	end

	mis_log.pure_day('rotate_tmp', t_params.uin)

	t_ret = {
		coin = t_spData[mis_config.t_specialItem.s_ROTATE] or 0;
		count = t_rotateData.num or 0;
		mission = next(t_misData) and t_misData or nil;
		nextTime = n_activateTime and (n_activateTime + n_refreshTime) or (n_now < mis_data.t_rotate.t_conf.n_endTime and n_now + mis_common.time_to_time(n_daily, n_now) or -1);
	}
	return t_retCode.n_OK, t_ret
end

--------------------------------------------------------------
-- 说明：转盘抽奖
-- 参数：createTime			建号时间
-- 返回：n					状态码
--		ts 					描述
this.rotate = function()
	local t_params = ngx.ctx.t_params
	local n_now, n_code, n_rand, n_selectId = ngx.time()
	local s_desc, sn_bonusId
	local s_coin = mis_config.t_specialItem.s_ROTATE
	local t_, t_basicData, t_spData, t_rotateData, t_ret
	local t_user, t_bonus = mis_data.get_user(), {}

	-- 扣费
	n_code, t_spData = t_user:get_specialItem_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_spData
	end
	if not t_spData[s_coin] or t_spData[s_coin] <= 0 then
		return t_retCode.n_OPER_ERR, 'insufficient money'
	end
	t_spData[s_coin] = t_spData[s_coin] - 1
	if t_spData[s_coin] == 0 then
		t_spData[s_coin] = nil
	end
	n_code, s_desc = t_user:set_specialItem_data(t_spData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 抽奖
	n_code, t_rotateData = t_user:get_rotate_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, t_rotateData
	end

	if t_params.rich then
		if (t_rotateData.coin and t_rotateData.coin >= 3) or n_now < t_params.createTime + 604800 or n_now < t_rotateData.activateTime + 172800 then -- 604800: 7 days, 172800: 2 days
			s_desc = 't_rotateRichNoCoin'
		else
			s_desc = 't_rotateRich'
		end
	else
		if (t_rotateData.coin and t_rotateData.coin >= 3) or n_now < t_params.createTime + 604800 or n_now < t_rotateData.activateTime + 172800 then -- 604800: 7 days, 172800: 2 days
			s_desc = 't_rotatePoorNoCoin'
		else
			s_desc = 't_rotatePoor'
		end
	end
	if not t_rotateData.num then
		-- 首次抽奖
		t_ = mis_data.t_rotate.t_conf.t_first
	else
		t_ = mis_data.t_rotate.t_conf.t_default
	end
	n_rand = math_random()
	for n_id, n_ratio in ipairs(t_[s_desc]) do
		if n_rand <= n_ratio then n_selectId = n_id; break end
	end
	t_ = t_.t_config[n_selectId]
	if t_.b_rand then
		if t_[1].id then
			t_bonus[#t_bonus+1] = t_[math_random(#t_)]
			if t_bonus[#t_bonus].id == 10002 then t_rotateData.coin = t_rotateData.coin and t_rotateData.coin + 1 or 1 end
			sn_bonusId = t_bonus[#t_bonus].id
		else
			for _, t_2 in pairs(t_[math_random(#t_)]) do
				t_bonus[#t_bonus+1] = t_2
				if t_2.id == 10002 then t_rotateData.coin = t_rotateData.coin and t_rotateData.coin + 1 or 1 end
				sn_bonusId = sn_bonusId and (sn_bonusId .. ',' .. t_2.id) or t_2.id
			end
		end
	else
		for _, t_2 in pairs(t_) do
			t_bonus[#t_bonus+1] = t_2
			if t_2.id == 10002 then t_rotateData.coin = t_rotateData.coin and t_rotateData.coin + 1 or 1 end
			sn_bonusId = sn_bonusId and (sn_bonusId .. ',' .. t_2.id) or t_2.id
		end
	end

	t_rotateData.num = t_rotateData.num and t_rotateData.num + 1 or 1
	n_code, s_desc = t_user:set_rotate_data(t_rotateData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 发道具
	n_code, s_desc = mis_data.add_items(t_params.uin, t_bonus, mis_config.t_workType.s_ROTATE, 'rotate')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('rotate', 'add_items_failed|' .. t_params.uin .. '|' .. mis_common.table_to_json(t_bonus))
		return n_code, s_desc
	end

	mis_log.remote_pure_day('rotate', mis_common.table_to_json({
		ip = t_params.s_remoteAddr;
		uin = t_params.uin;
		time = n_now;
		country = t_params.country;
		apiid = t_params.apiid;
		ver = t_params.ver;
		lang = t_params.lang;
		areaid = n_selectId;
		bonusId = sn_bonusId;
	}))

	-- 响应
	t_ret = {
		id = n_selectId;
		coin = t_spData[s_coin] or 0;
		count = t_rotateData.num or 0;
		bonus = t_bonus;
	}
	return t_retCode.n_OK, t_ret
end

--------------------------------------------------------------
-- 说明：导流业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_diversion = function()
	if mis_data.t_diversion.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'diversion disable'
	end

	-- 渠道控制
	local t_params  		= ngx.ctx.t_params
	local t_diversionConf 	= mis_data.t_diversion.t_conf

	if t_diversionConf.apiids then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)
		local t_apiids = mis_uu.split(t_diversionConf.apiids, ',')
		for _, v in pairs(t_apiids) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if not b_valid_apiid then
			return t_retCode.n_OPER_ERR, 'apiid is invalid'
		end
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：触发导流事件
-- 参数：event				事件id
-- 返回：n					状态码
--		ts 					描述
this.diversion_event = function()
	local t_params 	= ngx.ctx.t_params
	local n_uin 	= t_params.uin
	local s_uin_list = t_params.uin_list
	local n_taskId 	= t_params.event
	local n_now 	= ngx.time()
	local n_leader  = 1000
	local t_conf 	= mis_data.t_diversion.t_conf.task or {}
	local n_code, st_desc, s_msg, t_divData
	
	if n_taskId == 1 then					-- 登陆事件
		n_code, st_desc = mis_bridge.query_profile_info(n_leader, n_uin)
		if n_code ~= t_retCode.n_OK or not st_desc then
			mis_log.day('diversion_error', 'query_profile_info failed|' .. n_uin .. '|event|' .. n_taskId)
			return n_code, st_desc
		end

		local t_profile = st_desc[1] and st_desc[1].profile
		if t_profile and t_profile.user_version and tonumber(t_profile.user_version) == 2 then
			local n_ret, s_desc = mis_bridge.set_profile_info(n_uin, 1)
			if n_ret ~= t_retCode.n_OK or not s_desc then
				mis_log.day('diversion_error', 'set_profile_info failed|' .. n_uin .. '|event|' .. n_taskId)
				return n_ret, s_desc
			end
		end

		if not (t_profile and t_profile.user_version and tonumber(t_profile.user_version) == 2) then
			local n_finish  	= 0
			local b_notify  	= true
			local t_user 		= mis_data.get_user(n_uin)
			n_code, t_divData 	= t_user:get_diversion_data()

			if n_code ~= t_retCode.n_OK then
				return n_code, t_divData
			end
			if t_divData and t_divData[n_taskId] and t_divData[n_taskId].finish and t_divData[n_taskId].time then
				if t_conf[n_taskId].weekly and not mis_common.is_another_week(t_divData[n_taskId].time, n_now) then
					n_finish = t_divData[n_taskId].finish
					if n_finish and n_finish >= t_conf[n_taskId].target then
						b_notify = false
					end
				end
				mis_log.debug('get_diversion_data|' .. mis_common.table_to_json(t_divData))
			end

			if b_notify then
				n_code, st_desc = mis_bridge.query_map_list()
				if n_code ~= t_retCode.n_OK or not st_desc then
					return n_code, st_desc
				end

				local s_map_name = ''
				local t_map = st_desc.list and st_desc.list[1]
				local s_content = t_conf[n_taskId].content or mis_config.t_message.t_diversion.s_content[n_taskId]
				if t_map then s_map_name = t_map.map_name or '' end

				s_msg = string.gsub(s_content, 'XXX', s_map_name)
				n_code, st_desc = mis_bridge.push_diversion_message(n_leader, n_uin, s_msg)
				if n_code ~= t_retCode.n_OK then
					return n_code, st_desc
				end

				t_divData 					= t_divData or {}
				t_divData[n_taskId] 		= t_divData[n_taskId] or {}
				t_divData[n_taskId].time 	= n_now
				t_divData[n_taskId].finish 	= n_finish + 1

				n_code, st_desc = t_user:set_diversion_data(t_divData)
				if n_code ~= t_retCode.n_OK then
					return n_code, st_desc
				end
				mis_log.day('diversion', 'uin|' .. n_uin .. '|event|' .. n_taskId .. '|' .. mis_common.table_to_json(t_divData))
			end
		end
	elseif n_taskId == 2 then				-- 游戏结束事件
		local  t_uin_ver1 , t_uin_ver2 = {}, {}
		n_code, st_desc = mis_bridge.query_profile_info(n_leader, s_uin_list)
		if n_code ~= t_retCode.n_OK or not st_desc then
			mis_log.day('diversion_error', 'query_profile_info failed|' .. n_uin .. '|event|' .. n_taskId)
			return n_code, st_desc
		end
		for k, v in pairs(st_desc) do
			if v and v.uin then
				if v.profile and v.profile.user_version and tonumber(v.profile.user_version) == 2 then
					if v.profile.RoleInfo and v.profile.RoleInfo.NickName then
						table_insert(t_uin_ver2, v.profile.RoleInfo.NickName)
					end
				else
					table_insert(t_uin_ver1, tonumber(v.uin))
				end
			end
		end

		if not mis_common.tableIsEmpty(t_uin_ver1) and not mis_common.tableIsEmpty(t_uin_ver2) then
			local n_count_ver1 = #t_uin_ver1
			local t_push_ver1  = {}
			for k, v in pairs(t_uin_ver1) do
				local n_finish  = 0
				local b_notify  = true
				local t_user 	= mis_data.get_user(v)

				n_code, t_divData = t_user:get_diversion_data()
				if n_code ~= t_retCode.n_OK then
					return n_code, t_divData
				end
				if t_divData and t_divData[n_taskId] and t_divData[n_taskId].finish and t_divData[n_taskId].time then
					if t_conf[n_taskId].daily and not mis_common.is_another_day(t_divData[n_taskId].time, n_now) then
						n_finish = t_divData[n_taskId].finish
						if n_finish and n_finish >= t_conf[n_taskId].target then
							b_notify = false
						end
					end
					mis_log.debug('get_diversion_data|' .. mis_common.table_to_json(t_divData))
				end

				if b_notify then
					t_divData 					= t_divData or {}
					t_divData[n_taskId] 		= t_divData[n_taskId] or {}
					t_divData[n_taskId].time 	= n_now
					t_divData[n_taskId].finish 	= n_finish + 1

					n_code, st_desc = t_user:set_diversion_data(t_divData)
					if n_code ~= t_retCode.n_OK then
						return n_code, st_desc
					end

					table_insert(t_push_ver1, tonumber(v))
					mis_log.day('diversion', 'uin|' .. v .. '|event|' .. n_taskId .. '|' .. mis_common.table_to_json(t_divData))
				end

				-- 批量推送
				if #t_push_ver1 >= 10 then
					local s_content = t_conf[n_taskId].content or mis_config.t_message.t_diversion.s_content[n_taskId]
					s_msg = string.gsub(s_content, 'XXX', t_uin_ver2[1])
					n_code, st_desc = mis_bridge.push_diversion_message(n_leader, table.concat(t_push_ver1, ",", 1), s_msg)
					if n_code ~= t_retCode.n_OK then
						return n_code, st_desc
					end
					t_push_ver1 = {}
				end
			end
			if #t_push_ver1 > 0 then
				local s_content = t_conf[n_taskId].content or mis_config.t_message.t_diversion.s_content[n_taskId]
				s_msg = string.gsub(s_content, 'XXX', t_uin_ver2[1])
				n_code, st_desc = mis_bridge.push_diversion_message(n_leader, table.concat(t_push_ver1, ",", 1), s_msg)
				if n_code ~= t_retCode.n_OK then
					return n_code, st_desc
				end
			end
		end
	end

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：twoback 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_twoback = function()
	if mis_data.t_twoback.n_status ~= mis_config.t_workStatus.n_ENABLE then
		log.day_list("twoback","pre_twoback-flag-1",ngx.ctx.t_params.uin)
		return t_retCode.n_OPER_ERR, 'twoback disable'
	end

	--现网屏蔽先
	--[[if mis_config.n_debug ~= 1 then
		return t_retCode.n_OPER_ERR, 'twoback disable2'
	end--]]

	local longconf 	= mis_data.t_twoback.t_conf_long
	local shortconf = mis_data.t_twoback.t_conf_short

	if longconf == nil or shortconf == nil then
		log.day_list("twoback","pre_twoback-flag-1-2",ngx.ctx.t_params.uin)
		return t_retCode.n_NO_DATA, 'twoback conf error'
	end

	local _desc
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_twobackData = t_user:get_twoback_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","pre_twoback-flag-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_twobackData))
		return n_code, t_twobackData
	end

	local n_now = uu.now()

	if t_twobackData.old_or_new == nil then
		t_twobackData.old_or_new = true --默认走新回流

		if t_user:check_back_data_is_have() then
			t_twobackData.old_or_new = false --以前有数据走老回流
			log.day_list("twoback","pre_twoback-flag-2-1-1",'以前有数据走老回流',ngx.ctx.t_params.uin)
		end

		-- ABTest
		if longconf.ABTest and t_twobackData.old_or_new then
			local n_bucketId, n_res = mis_data.t_ABTestSDK.getABTestExp(longconf.ABTest, t_params.uin)
			if not n_bucketId or n_res ~= 1 then
				t_twobackData.old_or_new = false --不中走老回流
				log.day_list("twoback","pre_twoback-flag-2-1-2",'ABTest不中',ngx.ctx.t_params.uin,uu.to_str(n_bucketId),uu.to_str(n_res))
			else
				log.day_list("twoback","pre_twoback-flag-2-1-3",'ABTest中',ngx.ctx.t_params.uin,uu.to_str(n_bucketId),uu.to_str(n_res))
			end

		end

		--[[if mis_config.n_debug == 1 then
			t_twobackData.old_or_new = true
		end--]]


		n_code, _desc = t_user:set_twoback_data(t_twobackData)
		--log.day_list("twoback","pre_twoback-flag-2-2-1",ngx.ctx.t_params.uin,uu.to_str(t_twobackData.old_or_new))
		if n_code ~= t_retCode.n_OK then
			log.day_list("twoback","pre_twoback-flag-2-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc))
			return n_code, _desc
		end

		t_user:add_read_lock(mis_config.t_ssdbKey.s_TWOBACK)  --后续可能有二次写，加一次虚拟锁
	end


	if t_twobackData.old_or_new == false then

		if t_user:check_twoback_or_oneback() then
			t_twobackData.old_or_new = true
		end

		if t_twobackData.old_or_new == false then
			log.day_list("twoback","pre_twoback-flag-2-3",ngx.ctx.t_params.uin,uu.to_str(t_twobackData))
			return 1, {old_or_new=t_twobackData.old_or_new} -- 走老回流
		else

			n_code, _desc = t_user:set_twoback_data(t_twobackData)
			t_user:add_read_lock(mis_config.t_ssdbKey.s_TWOBACK)  --后续可能有二次写，加一次虚拟锁
		end

	end

	if t_twobackData.type == nil then
		--有新手任务就不给回流
		local novicen_code, novicet_userData = t_user:get_novice_task_data(true)
		if novicen_code ~= t_retCode.n_OK then
			return novicen_code, 'get user novice_task data error_twoback'
		end
		if novicet_userData.accept_end_time and n_now <= novicet_userData.accept_end_time then
			mis_log.print("fucktestxinshou","flag-1:",ngx.ctx.t_params.uin,n_now,novicet_userData.accept_end_time)
			return t_retCode.n_OPER_ERR, "now_is_novice_date_1_accept_expire"
		end
		if novicet_userData.notice_end_time and n_now <= novicet_userData.notice_end_time then
			mis_log.print("fucktestxinshou","flag-2:",ngx.ctx.t_params.uin,n_now,novicet_userData.notice_end_time)
			return t_retCode.n_OPER_ERR, "now_is_novice_date_2_expire"
		end
		
	end

	-- 黑名单检查
	if not t_twobackData.black then
		-- 查询数据库
		n_code, _desc = t_user:is_black()
		if n_code ~= t_retCode.n_OK then
			log.day_list("twoback","pre_twoback-flag-3",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc))
			return t_retCode.n_DB_ERR, 'check black failed'
		end
		t_twobackData.black = _desc
		if t_twobackData.black == 1 then
			n_code, _desc = t_user:set_twoback_data(t_twobackData)
			if n_code ~= t_retCode.n_OK then
				log.day_list("twoback","pre_twoback-flag-4",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc))
				return n_code, _desc
			end
			t_user:add_read_lock(mis_config.t_ssdbKey.s_TWOBACK)  --后续可能有二次写，加一次虚拟锁
		end
	end
	if t_twobackData.black == 1 then
		log.day_list("twoback","pre_twoback-flag-5",ngx.ctx.t_params.uin,uu.to_str(t_twobackData))
		return t_retCode.n_AUTH_ERR
	end

	-- 回归系统状态判定
	if not t_twobackData.loginTime then
		-- 查询数据库
		n_code, _desc = t_user:get_user_basic()
		if n_code == t_retCode.n_NO_DATA then
			t_twobackData.loginTime = n_now
		elseif n_code == t_retCode.n_OK then
			t_twobackData.loginTime = tonumber(_desc.last_login_time) or n_now
		else
			log.day_list("twoback","pre_twoback-flag-6",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc))
			return n_code, _desc
		end
	else
		t_twobackData.loginTime = tonumber(t_twobackData.loginTime)
	end



	if t_twobackData.type == nil then
		local pre_day = math_floor((n_now - t_twobackData.loginTime)/86400)


		if pre_day >= longconf.lost_day then
			t_twobackData.type = 3 --长流失
			t_twobackData.aimconf = longconf
			log.day_list("twoback","pre_twoback-flag-6-1",ngx.ctx.t_params.uin)
		else
			if pre_day >= shortconf.lost_day then
				t_twobackData.type = 4 --短流失
				t_twobackData.aimconf = shortconf
				log.day_list("twoback","pre_twoback-flag-6-2",ngx.ctx.t_params.uin)
			end
		end

		if t_twobackData.type ~= nil then
			--埋点数据
					mis_log.remote_pure_day('twoback', mis_common.table_to_json({
							key = 'start';
							ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
							uin = t_params.uin;
							time = uu.now();
							country = t_params.country or 'nil';
							apiid = t_params.apiid or 'nil';
							ver = t_params.ver or 'nil';
							lang = t_params.lang or 'nil';
							labelid = t_twobackData.type;
							taskid = 'nil';
							bonusid= 'nil';
						}))
		end
		
		--内网测试
		--[[if mis_config.n_debug == 1 then
			t_twobackData.type = 3 --长流失
			t_twobackData.aimconf = longconf
		end--]]
	end


	if t_twobackData.type == nil or t_twobackData.aimconf == nil then
		log.day_list("twoback","pre_twoback-flag-7",ngx.ctx.t_params.uin,uu.to_str(t_twobackData))
		return t_retCode.n_NO_DATA
	end

	if t_twobackData.type == 3 and longconf.has_back_flag_year and longconf.has_back_flag_year == 1 then
		--还要再判断一年内是否是频繁刷流失的情况
		if t_twobackData.last_do_twoback_time then
			local pre_day = math_floor((n_now - t_twobackData.last_do_twoback_time)/86400)
			if pre_day <= 365 then
				t_twobackData.type = 4 --设为短流失
				t_twobackData.aimconf = shortconf
			end
		end

	end

	--查看当前配置是否取最新的
	local new_conf = shortconf
	if t_twobackData.type == 3 then
		new_conf = longconf
	end

	if t_twobackData.aimconf.startTime ~= new_conf.startTime or t_twobackData.aimconf.endTime ~= new_conf.endTime then
		t_twobackData.aimconf = new_conf
	end

	-- 版本号控制
	if t_twobackData.aimconf.ver_min then
		local n_l = mis_common.version_to_number(t_params.ver or 0)
		local n_r = mis_common.version_to_number(t_twobackData.aimconf.ver_min or 0)
		if n_l < n_r then
			log.day_list("twoback","pre_twoback-flag-8",ngx.ctx.t_params.uin,uu.to_str(t_twobackData.aimconf.ver_min),uu.to_str(t_params.ver))
			return t_retCode.n_OPER_ERR, 'version too low'
		end
	end

	--判断是否已超过可做天数
	if t_twobackData.get_twoback_task_time then
		local pre_day = math_floor((n_now - t_twobackData.get_twoback_task_time)/86400)
		if pre_day >= t_twobackData.aimconf.mission_day then

			n_code, _desc = t_user:set_twoback_data({last_do_twoback_time = n_now,old_or_new = true})

			if n_code == t_retCode.n_OK then
				log.day_list("twoback","pre_twoback-flag-9",ngx.ctx.t_params.uin,uu.to_str(t_twobackData.get_twoback_task_time),uu.to_str(n_now))
				return t_retCode.n_NO_DATA
			else
				log.day_list("twoback","pre_twoback-flag-10",ngx.ctx.t_params.uin,uu.to_str(t_twobackData.get_twoback_task_time),uu.to_str(n_now),uu.to_str(n_code))
				return n_code, _desc
			end

			t_user:add_read_lock(mis_config.t_ssdbKey.s_TWOBACK)  --后续可能有二次写，加一次虚拟锁
		end
	end

	--判断是否在任务阶段时间内
	local flag_opentime = mis_common.date_to_unix(t_twobackData.get_task_opentime or t_twobackData.aimconf.startTime)
	local flag_closetime = mis_common.date_to_unix(t_twobackData.get_task_closetime or t_twobackData.aimconf.endTime)
	if n_now < flag_opentime or n_now > flag_closetime then
		log.day_list("twoback","pre_twoback-flag-10-1",ngx.ctx.t_params.uin,uu.to_str(t_twobackData.get_task_opentime),uu.to_str(t_twobackData.get_task_closetime),
			uu.to_str(t_twobackData.aimconf.startTime),uu.to_str(t_twobackData.aimconf.endTime))
		return t_retCode.n_NO_DATA, 'is_not_task_time' -- 不在任务期
	end

	n_code, _desc = t_user:set_twoback_data(t_twobackData)
	--log.day_list("twoback","pre_twoback-flag-11",ngx.ctx.t_params.uin)
	return n_code, _desc
end

--------------------------------------------------------------
-- 说明：二期回流任务触发核心
-- 返回：n					状态码
--		ts 					描述
local function task_twoback_core(n_event,t_twobackData)

	local flag_qipao = false
	local flag_total = 7
	local t_params  		= ngx.ctx.t_params
	if t_twobackData.task[n_event] and n_event ~= flag_total then


		for i=1,#t_twobackData.task[n_event].target_bonus do
			if t_twobackData.task[n_event].target_bonus[i] then
				if t_twobackData.task[n_event].target_bonus[i].do_num < t_twobackData.task[n_event].target_bonus[i].target then
					t_twobackData.task[n_event].target_bonus[i].do_num = t_twobackData.task[n_event].target_bonus[i].do_num + 1
					log.day_list("twoback","task_twoback_core-flag-1-",t_params.uin,n_event,uu.to_str(t_twobackData.task[n_event].target_bonus[i]))
					if t_twobackData.task[n_event].target_bonus[i].status == 0 and
						t_twobackData.task[n_event].target_bonus[i].do_num >= t_twobackData.task[n_event].target_bonus[i].target then
					t_twobackData.task[n_event].target_bonus[i].status = mis_config.t_missionStatus.n_DONE
					flag_qipao = true

					--埋点数据
					mis_log.remote_pure_day('twoback', mis_common.table_to_json({
							key = 'complete';
							ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
							uin = t_params.uin;
							time = uu.now();
							country = t_params.country or 'nil';
							apiid = t_params.apiid or 'nil';
							ver = t_params.ver or 'nil';
							lang = t_params.lang or 'nil';
							labelid = t_twobackData.type;
							taskid = n_event;
							bonusid= 'nil';
						}))


					--完成一次后,判断是否要叠加一次总奖励

					if t_twobackData.task[flag_total].target_bonus[1].do_num < t_twobackData.task[flag_total].target_bonus[1].target then
						t_twobackData.task[flag_total].target_bonus[1].do_num = t_twobackData.task[flag_total].target_bonus[1].do_num + 1

						if t_twobackData.task[flag_total].target_bonus[1].status == 0 and
							t_twobackData.task[flag_total].target_bonus[1].do_num >= t_twobackData.task[flag_total].target_bonus[1].target then
								t_twobackData.task[flag_total].target_bonus[1].status = mis_config.t_missionStatus.n_DONE
						end

						--埋点数据
					mis_log.remote_pure_day('twoback', mis_common.table_to_json({
							key = 'complete';
							ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
							uin = t_params.uin;
							time = uu.now();
							country = t_params.country or 'nil';
							apiid = t_params.apiid or 'nil';
							ver = t_params.ver or 'nil';
							lang = t_params.lang or 'nil';
							labelid = t_twobackData.type;
							taskid = 7;
							bonusid= 'nil';
						}))
					log.day_list("twoback","task_twoback_core-flag-2-",t_params.uin,flag_total,uu.to_str(t_twobackData.task[flag_total].target_bonus[1]))

					end
				end

				if t_twobackData.task[n_event].target_bonus[i].time then --有联机时长的情况特殊处理
					break
				end

				end
			end
		end

	end

	return t_twobackData, flag_qipao
end

--------------------------------------------------------------
-- 说明：检测指定回流任务事件是否完成
-- 返回：n					状态码
--		ts 					描述
local check_twoback_task_trigger = function(t_twobackData, n_event)
	local b_bindTrigger = false

	if not(t_twobackData and mis_uu.tableNotEmpty(t_twobackData) and n_event) then
		return false
	end

	for _, t_task in pairs(t_twobackData.task or {}) do
		if t_task.event and t_task.event == n_event then
			b_bindTrigger = true
			for k, v in pairs(t_task.target_bonus or {}) do
				if v.do_num >= v.target then
					b_bindTrigger = false
				else
					b_bindTrigger = true
					break
				end
			end
		end
		if b_bindTrigger then
			break
		end
	end
	--mis_log.day("task_trigger","check_twoback_task_trigger|" .. ngx.ctx.t_params.uin .. '|' .. (b_bindTrigger and 'true' or 'false'))
	return b_bindTrigger
end

--------------------------------------------------------------
-- 说明：获取玩家二期回流当前状态
-- 返回：n					状态码
--		ts 					描述
this.twoback_get_task_status = function()

	local _desc
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_twobackData = t_user:get_twoback_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","twoback_get_task_status-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_twobackData))
		return n_code, t_twobackData
	end

	local n_now = uu.now()
	--前面已经判断是否是回归玩家了,这里直接领了
	if t_twobackData.get_twoback_task_time == nil or t_twobackData.get_twoback_task_time == 0 then
		t_twobackData.get_task_opentime = t_twobackData.aimconf.startTime
		t_twobackData.get_task_closetime = t_twobackData.aimconf.endTime

		t_twobackData.get_twoback_task_time = n_now
		t_twobackData.get_twoback_task_time_end = n_now + t_twobackData.aimconf.mission_day*86400

		t_twobackData.day_time = n_now --初次请求数据的时间戳

		t_twobackData.task = {}
		for k,v in pairs(t_twobackData.aimconf.mission) do
			t_twobackData.task[v.event] = v

			for i,j in pairs(t_twobackData.task[v.event].target_bonus) do
				t_twobackData.task[v.event].target_bonus[i].do_num = 0
				t_twobackData.task[v.event].target_bonus[i].status = 0 -- 0：未完成，1：已完成（待领取），2：已领取
			end

		end


	end

	if uu.compareTimes(n_now, t_twobackData.day_time) == false then
		--代表不是同一天
		--此时要刷新每日任务
		t_twobackData.day_time = n_now


		--每天去确认配置日期
		if t_twobackData.aimconf.startTime == t_twobackData.get_task_opentime and
			t_twobackData.aimconf.endTime == t_twobackData.get_task_closetime then

				--获取当前最新配置
				local longconf 	= mis_data.t_twoback.t_conf_long
				local shortconf = mis_data.t_twoback.t_conf_short
				t_twobackData.aimconf = shortconf
				if t_twobackData.type == 3 then
					t_twobackData.aimconf = longconf
				end

			for k,v in pairs(t_twobackData.aimconf.mission) do

				if t_twobackData.task[v.event] then
					for i,j in pairs(t_twobackData.task[v.event].target_bonus) do

						if v.target_bonus[i] then
							if t_twobackData.task[v.event].target_bonus[i].target and v.target_bonus[i].target then
						t_twobackData.task[v.event].target_bonus[i].target = v.target_bonus[i].target

						--累计奖励特殊处理
						if v.event == 7 then
							if t_twobackData.task[v.event].target_bonus[i][1] and v.target_bonus[i][1] then
								t_twobackData.task[v.event].target_bonus[i][1] = v.target_bonus[i][1]
							end
							if t_twobackData.task[v.event].target_bonus[i][2] and v.target_bonus[i][2] then
								t_twobackData.task[v.event].target_bonus[i][2] = v.target_bonus[i][2]
							end
							if t_twobackData.task[v.event].target_bonus[i][2] and v.target_bonus[i][2] then
								t_twobackData.task[v.event].target_bonus[i][2] = v.target_bonus[i][2]
							end

						end
					end

					if t_twobackData.task[v.event].target_bonus[i].id and v.target_bonus[i].id then
						t_twobackData.task[v.event].target_bonus[i].id = v.target_bonus[i].id
					end

					if t_twobackData.task[v.event].target_bonus[i].num and v.target_bonus[i].num then
						t_twobackData.task[v.event].target_bonus[i].num = v.target_bonus[i].num
					end
						end


				end
				end

			end

		end



		for k,v in pairs(t_twobackData.task) do
			if v.every_task_flag == 1 and t_twobackData.task[v.event] and t_twobackData.task[v.event].target_bonus then

				for i,j in pairs(t_twobackData.task[v.event].target_bonus) do
					t_twobackData.task[v.event].target_bonus[i].do_num = 0
					t_twobackData.task[v.event].target_bonus[i].status = 0 -- 0：未完成，1：已完成（待领取），2：已领取
				end

			end
		end

	end

	local flag_qipao = false

	t_twobackData, flag_qipao = task_twoback_core(18,t_twobackData)--18代表每日登录事件ID

	-- 检测绑定手机号任务，未完成手动触发
	if check_twoback_task_trigger(t_twobackData, 60) and mis_bridge.query_bind_phone(t_params.uin) then
		t_twobackData, flag_qipao = task_twoback_core(60,t_twobackData)
	end

	--开始查找当前是否有哪些任务已完成可领取的红点气泡
	for k,v in pairs(t_twobackData.task) do
		for i,j in pairs(v.target_bonus) do
			if j.do_num >= j.target and j.status == mis_config.t_missionStatus.n_DONE then
				flag_qipao = true
				break
			end
		end
		if flag_qipao == true then
			break
		end
	end

	--控制拍脸
	local slapface_flag = false
	if t_twobackData.slapface == nil then
		t_twobackData.slapface = false
		slapface_flag = true
	end

	--新拍脸,原来的老拍脸slapface就不动
	local new_slapface_type =t_twobackData.new_slapface_type or 0 --0不拍脸,1地图拍脸,2奖励拍脸

	local n_l = mis_common.version_to_number(t_params.ver or 0)
	local n_r = mis_common.version_to_number('1.14.0' or 0)
	if n_l >= n_r then
		if t_twobackData.new_slapface_type == nil then

			--[[local longconf 	= mis_data.t_twoback.t_conf_long
			if longconf.ABTest_face1 then
				local n_bucketId, n_res = mis_data.t_ABTestSDK.getABTestExp(longconf.ABTest_face1, t_params.uin)
				if not n_bucketId or n_res ~= 1 then
					--地图拍脸没中
					log.day_list("twoback","twoback_get_task_status-flag-3",'AB地图不中',ngx.ctx.t_params.uin,uu.to_str(n_bucketId),uu.to_str(n_res))
				else
					new_slapface_type = 1
					log.day_list("twoback","twoback_get_task_status-flag-4",'AB地图中',ngx.ctx.t_params.uin,uu.to_str(n_bucketId),uu.to_str(n_res))
				end
			end

			--依然还等于0,那就继续走
			if longconf.ABTest_face2 and new_slapface_type == 0 then
				local n_bucketId, n_res = mis_data.t_ABTestSDK.getABTestExp(longconf.ABTest_face2, t_params.uin)
				if not n_bucketId or n_res ~= 1 then
					--地图拍脸没中
					log.day_list("twoback","twoback_get_task_status-flag-5",'AB奖励不中',ngx.ctx.t_params.uin,uu.to_str(n_bucketId),uu.to_str(n_res))
				else
					new_slapface_type = 2
					log.day_list("twoback","twoback_get_task_status-flag-6",'AB奖励中',ngx.ctx.t_params.uin,uu.to_str(n_bucketId),uu.to_str(n_res))
				end
			end--]]
			--取消AB，写死这个实验得全量
			new_slapface_type = 2
			t_twobackData.new_slapface_type = new_slapface_type
			t_twobackData.new_slapface_type_count = 1 --此次是必拍的,先默认为1次

		else
			--已经有了,先暂时不拍
			new_slapface_type = 0

			--特殊情况还能再拍一次(总共两次)
			--次日后，若本次回流期间尚未进行联机地图，则当日首次登录时再拍一次
			if t_twobackData.new_slapface_type_count == 1 and 
				t_twobackData.email == nil and 
				t_twobackData.day_time == n_now then

				new_slapface_type = t_twobackData.new_slapface_type
				t_twobackData.new_slapface_type_count = 2 --拍第二次了

			end


		end

	end

	n_code, _desc = t_user:set_twoback_data(t_twobackData)

	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","twoback_get_task_status-flag-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_twobackData))
		return n_code, _desc
	end
	--log.day_list("twoback","twoback_get_task_status-flag-3",ngx.ctx.t_params.uin,uu.to_str(flag_qipao))
	return t_retCode.n_OK, {flag_qipao = flag_qipao,task = t_twobackData.task,
	old_or_new = t_twobackData.old_or_new or true,
	start_time = t_twobackData.get_twoback_task_time,
	end_time = t_twobackData.get_twoback_task_time_end,
	type = t_twobackData.type,
	slapface = slapface_flag,
	new_slapface_type=new_slapface_type}

end

--------------------------------------------------------------
-- 说明：获取玩家当前任务主界面
-- 返回：n					状态码
--		ts 					描述
this.twoback_get_task_main_task = function()
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_twobackData = t_user:get_twoback_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","twoback_get_task_main_task-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_twobackData))
		return n_code, t_twobackData
	end

	local data=
	{
		start_time = t_twobackData.get_twoback_task_time,
		end_time = t_twobackData.get_twoback_task_time_end,
		task = t_twobackData.task,
	}

	local n_now = uu.now()

	--log.day_list("twoback","twoback_get_task_main_task-flag-2",ngx.ctx.t_params.uin)
	return t_retCode.n_OK, data
end

--------------------------------------------------------------
-- 说明：二期回流任务触发
-- 返回：n					状态码
--		ts 					描述
this.twoback_task_event = function()
	local t_params  		= ngx.ctx.t_params
	local s_desc
	local t_user = mis_data.get_user()
	local n_code, t_twobackData = t_user:get_twoback_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","twoback_task_event-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_twobackData))
		return n_code, t_twobackData
	end

	if t_twobackData.task == nil or uu.tableIsEmpty(t_twobackData.task) then
		log.day_list("twoback","twoback_task_event-flag-1-1",ngx.ctx.t_params.uin,uu.to_str(t_twobackData))
		return t_retCode.n_NO_DATA
	end

	-- [特例]
	-- 如果是首次联机，发送奖励邮件
	if t_params.event == 9 and not t_twobackData.email then
		local t_mailConf = mis_config.t_twobackMail

		local n_last =(t_twobackData.get_twoback_task_time or t_twobackData.loginTime )+ (t_twobackData.aimconf.mission_day * 86400) - ngx.time()
		n_code, s_desc = mis_bridge.send_email(t_params.uin, t_mailConf.s_title,
							t_mailConf.s_body, n_last, t_twobackData.aimconf.first_online_award, t_mailConf.n_jumpTo)

		if n_code ~= t_retCode.n_OK then
			log.day_list("twoback","twoback_task_event-flag-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(s_desc))
			return n_code, s_desc
		end
		t_twobackData.email = 1
		n_code, s_desc = t_user:set_back_data(t_twobackData)
		if n_code ~= t_retCode.n_OK then
			log.day_list("twoback","twoback_task_event-flag-3",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(t_twobackData))
			return n_code, s_desc
		end
	end


	local t_twobackData, flag_qipao = task_twoback_core(t_params.event,t_twobackData)
	local _desc
	n_code, _desc = t_user:set_twoback_data(t_twobackData)

	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","twoback_task_event-flag-4",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_twobackData))
		return n_code, _desc
	end
	--log.day_list("twoback","twoback_task_event-flag-5",ngx.ctx.t_params.uin,uu.to_str(flag_qipao),uu.to_str(t_params.event))
	return t_retCode.n_OK, {flag_qipao = flag_qipao or false,task = t_twobackData.task}

end

--------------------------------------------------------------
-- 说明：二期回流任务领取
-- 返回：n					状态码
--		ts 					描述
this.twoback_getaward = function()
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_twobackData = t_user:get_twoback_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","twoback_getaward-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_twobackData))
		return n_code, t_twobackData
	end

	if t_twobackData.task == nil or uu.tableIsEmpty(t_twobackData.task) then
		log.day_list("twoback","twoback_getaward-flag-1-1",ngx.ctx.t_params.uin,uu.to_str(t_twobackData))
		return t_retCode.n_NO_DATA
	end

	local items={}
	local s_desc = 1
	local _desc = 1
	if t_twobackData.task[t_params.event] then

		for k,v in pairs(t_twobackData.task[t_params.event].target_bonus) do

			if v.target == t_params.target and v.status == mis_config.t_missionStatus.n_DONE then
				t_twobackData.task[t_params.event].target_bonus[k].status = mis_config.t_missionStatus.n_PICKED

				if t_params.event == 7 and t_params.flag_number then
					t_params.flag_number = tonumber(t_params.flag_number)
					items =
					{
						{
							id=t_twobackData.task[t_params.event].target_bonus[k][t_params.flag_number][1].id,
				 			num=t_twobackData.task[t_params.event].target_bonus[k][t_params.flag_number][1].num
						},
						{
							id=t_twobackData.task[t_params.event].target_bonus[k][t_params.flag_number][2].id,
				 			num=t_twobackData.task[t_params.event].target_bonus[k][t_params.flag_number][2].num
						}
					}

					t_twobackData.task[t_params.event].flag_number = t_params.flag_number

				else
					items =
					{
						{
							id=t_twobackData.task[t_params.event].target_bonus[k].id,
				 			num=t_twobackData.task[t_params.event].target_bonus[k].num
						}
					}
				end

				--埋点数据
					mis_log.remote_pure_day('twoback', mis_common.table_to_json({
							key = 'finish';
							ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
							uin = t_params.uin;
							time = uu.now();
							country = t_params.country or 'nil';
							apiid = t_params.apiid or 'nil';
							ver = t_params.ver or 'nil';
							lang = t_params.lang or 'nil';
							labelid = t_twobackData.type;
							taskid = t_params.event;
							bonusid= items;
						}))

				break
			end
		end
	end

	if uu.tableNotEmpty(items) and uu.tableNotEmpty(items[1]) then
		n_code, _desc = t_user:set_twoback_data(t_twobackData)
		if n_code ~= t_retCode.n_OK then
			log.day_list("twoback","twoback_getaward-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_twobackData))
			return n_code, t_twobackData
		end
	end

	n_code, s_desc = mis_data.add_items(t_params.uin, items, mis_config.t_workType.s_TWOBACK, 'twoback_getaward')
	if n_code ~= t_retCode.n_OK then
		log.day_list("twoback","twoback_getaward-flag-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(items))
		return n_code, s_desc
	end

	local data={
		items=items,
	}
	log.day_list("twoback","twoback_getaward-flag-3",ngx.ctx.t_params.uin,uu.to_str(data))
	return t_retCode.n_OK, data

end


--------------------------------------------------------------
-- 说明：nationalday 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_nationalday = function()
	if mis_data.t_nationalday.n_status ~= mis_config.t_workStatus.n_ENABLE then
		log.day_list("nationalday","pre_nationalday-flag-1",ngx.ctx.t_params.uin)
		return t_retCode.n_OPER_ERR, 'nationalday disable'
	end
	local conf 	= mis_data.t_nationalday.t_conf
	if conf == nil then
		log.day_list("nationalday","pre_nationalday-flag-1-2",ngx.ctx.t_params.uin)
		return t_retCode.n_NO_DATA, 'nationalday conf error'
	end
	local n_now = uu.now()
	--判断总活动时间
	local flag_opentime = mis_common.date_to_unix(conf.startTime or '1997-01-01')
	local flag_closetime = mis_common.date_to_unix(conf.endTime or '1997-01-01')
	if n_now < flag_opentime or n_now > flag_closetime then
		--log.day_list("nationalday","pre_nationalday-flag-2",ngx.ctx.t_params.uin,uu.to_str(conf.startTime),uu.to_str(conf.endTime),n_now)
		return t_retCode.n_NO_DATA, 'is_not_nationalday_time' -- 不在任务期
	end

	return t_retCode.n_OK
end


--领取与任务触发有个时间段
local function check_nationalday_get_coretime()
	local n_now = uu.now()
	local conf 	= mis_data.t_nationalday.t_conf
	local flag_endtime = mis_common.date_to_unix(conf.task_endTime or '1997-01-01')
	if n_now > flag_endtime then
		log.day_list("nationalday","check_nationalday_get_coretime-flag-1",ngx.ctx.t_params.uin,uu.to_str(flag_endtime),n_now)
		return false
	end
	return true
end

--------------------------------------------------------------
-- 说明：国庆任务触发核心
-- 返回：n					状态码
--		ts 					描述
local function task_nationalday_core(n_event,t_nationaldayData)
	local t_params = ngx.ctx.t_params
	local flag_qipao = false

	if t_nationaldayData.task and check_nationalday_get_coretime() then
		for k,v in pairs(t_nationaldayData.task) do
		if v.event == n_event and v.do_num < v.target then
			t_nationaldayData.task[k].do_num = t_nationaldayData.task[k].do_num + 1

			if n_event == 22 and v.time then
				if t_nationaldayData.task[k].flag_t == nil then
					t_nationaldayData.task[k].flag_t = 0
				end
				t_nationaldayData.task[k].flag_t = t_nationaldayData.task[k].flag_t + 60 --客户端60秒上报一次

				--不符合要求重新减去
				if t_nationaldayData.task[k].flag_t < v.time then
					t_nationaldayData.task[k].do_num = t_nationaldayData.task[k].do_num - 1
				else
					t_nationaldayData.task[k].flag_t = 0
				end

			end


			if v.status == 0 and t_nationaldayData.task[k].do_num >= v.target then
				t_nationaldayData.task[k].status = mis_config.t_missionStatus.n_DONE
				flag_qipao = true

				mis_log.remote_pure_day('nationalday', mis_common.table_to_json({
							key = 'complete';
							ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
							uin = t_params.uin;
							time = uu.now();
							country = t_params.country or 'nil';
							apiid = t_params.apiid or 'nil';
							ver = t_params.ver or 'nil';
							lang = t_params.lang or 'nil';
							taskId = n_event;
						}))

				log.day_list("nationalday","task_nationalday_core",ngx.ctx.t_params.uin,n_event)
			end

			if n_event == 2 then
				break
			end

		end
	end
	end



	return t_nationaldayData, flag_qipao
end

--------------------------------------------------------------
-- 说明：获取玩家国庆活动当前状态
-- 返回：n					状态码
--		ts 					描述
this.nationalday_get_task_status = function()

	local _desc,s_desc
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_nationaldayData = t_user:get_nationalday_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("nationalday","nationalday_get_task_status-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_nationaldayData))
		return n_code, t_nationaldayData
	end

	local n_now = uu.now()

	--获取最新配置
	local conf 	= mis_data.t_nationalday.t_conf

	if t_nationaldayData.task == nil then
		t_nationaldayData.task = {}

		for i=1,#conf.mission do
			if conf.mission[i] then
				local flag_opentime = mis_common.date_to_unix(conf.mission[i].startTime or '1997-01-01')
				local flag_closetime = mis_common.date_to_unix(conf.mission[i].endTime or '1997-01-01')

				--符合预期时间内才接受
				if n_now >= flag_opentime and n_now <= flag_closetime then
					t_nationaldayData.task[#t_nationaldayData.task + 1] = uu.table_value_copy(conf.mission[i])
				end
			end


		end


		for k,v in pairs(t_nationaldayData.task) do
			t_nationaldayData.task[k].do_num = 0
			t_nationaldayData.task[k].status = 0 --0：未完成，1：已完成（待领取），2：已领取

		end
		t_nationaldayData.day_time = n_now --初次请求数据的时间戳
		t_nationaldayData.total_coupons = 0--身上当前游园券
	end


	if uu.compareTimes(n_now, t_nationaldayData.day_time) == false then
		--代表不是同一天
		--此时要刷新每日任务
		t_nationaldayData.day_time = n_now

		local items = {}--第二天没领取的要帮忙领

		for k,v in pairs(t_nationaldayData.task) do
			if v.do_num >= v.target and v.status == mis_config.t_missionStatus.n_DONE then
				table.insert(items,{id = 12931, num = v.coupons})--这边写死游园券的ID，只是显示用
				t_nationaldayData.total_coupons = t_nationaldayData.total_coupons + v.coupons
			end
		end

		t_nationaldayData.task = {}

		for i=1,#conf.mission do
			if conf.mission[i] then
				local flag_opentime = mis_common.date_to_unix(conf.mission[i].startTime or '1997-01-01')
				local flag_closetime = mis_common.date_to_unix(conf.mission[i].endTime or '1997-01-01')

				--符合预期时间内才接受
				if n_now >= flag_opentime and n_now <= flag_closetime then
					t_nationaldayData.task[#t_nationaldayData.task + 1] = uu.table_value_copy(conf.mission[i])
				end
			end


		end




		for k,v in pairs(t_nationaldayData.task) do
			t_nationaldayData.task[k].do_num = 0
			t_nationaldayData.task[k].status = 0 --0：未完成，1：已完成（待领取），2：已领取
		end

		t_user:set_nationalday_data(t_nationaldayData)

	end

	local flag_qipao = false

	t_nationaldayData, flag_qipao = task_nationalday_core(18,t_nationaldayData)--18代表每日登录事件ID

	--开始查找当前是否有哪些任务已完成可领取的红点气泡
	for k,v in pairs(t_nationaldayData.task) do
		if v.do_num >= v.target and v.status == mis_config.t_missionStatus.n_DONE then
			flag_qipao = true
		end
	end


	n_code, _desc = t_user:set_nationalday_data(t_nationaldayData)
	t_nationaldayData.map=conf.map
	if n_code ~= t_retCode.n_OK then
		log.day_list("nationalday","nationalday_get_task_status-flag-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_nationaldayData))
		return n_code, _desc
	end
	--log.day_list("nationalday","nationalday_get_task_status-flag-3",ngx.ctx.t_params.uin,uu.to_str(flag_qipao))
	return t_retCode.n_OK, {flag_qipao = flag_qipao or false,all_data = t_nationaldayData}

end

--------------------------------------------------------------
-- 说明：国庆任务触发
-- 返回：n					状态码
--		ts 					描述
this.nationalday_task_event = function()
	local t_params  		= ngx.ctx.t_params
	local s_desc
	local t_user = mis_data.get_user()
	local n_code, t_nationaldayData = t_user:get_nationalday_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("nationalday","nationalday_task_event-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_nationaldayData))
		return n_code, t_nationaldayData
	end


	local t_nationaldayData, flag_qipao = task_nationalday_core(t_params.event,t_nationaldayData)
	local _desc
	n_code, _desc = t_user:set_nationalday_data(t_nationaldayData)

	if n_code ~= t_retCode.n_OK then
		log.day_list("nationalday","nationalday_task_event-flag-4",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_nationaldayData))
		return n_code, _desc
	end
	--log.day_list("nationalday","nationalday_task_event-flag-5",ngx.ctx.t_params.uin,uu.to_str(flag_qipao))

	return t_retCode.n_OK, {flag_qipao = flag_qipao or false,all_data = t_nationaldayData}

end

--------------------------------------------------------------
-- 说明：国庆任务领取奖励
-- 返回：n					状态码
--		ts 					描述
this.nationalday_getaward = function()
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_nationaldayData = t_user:get_nationalday_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("nationalday","nationalday_getaward-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_nationaldayData))
		return n_code, t_nationaldayData
	end

	--领取有个时间段
	if check_nationalday_get_coretime() == false then
		log.day_list("nationalday","nationalday_getaward-flag-1-2",ngx.ctx.t_params.uin)
		return t_retCode.n_NO_DATA, 'is_not_nationalday_task_time' -- 不在任务期
	end


	local items={}
	local s_desc=1
	local _desc = 1

	if t_params.task_number and t_nationaldayData.task and t_nationaldayData.task[t_params.task_number] then

		if t_nationaldayData.task[t_params.task_number].status == mis_config.t_missionStatus.n_DONE then
			t_nationaldayData.task[t_params.task_number].status = mis_config.t_missionStatus.n_PICKED
				t_nationaldayData.total_coupons = t_nationaldayData.total_coupons + t_nationaldayData.task[t_params.task_number].coupons
				table.insert(items,{
					id=12931,
					num=t_nationaldayData.task[t_params.task_number].coupons
				})
		end

	end



	if uu.tableNotEmpty(items) then
		n_code, _desc = t_user:set_nationalday_data(t_nationaldayData)
		if n_code ~= t_retCode.n_OK then
			log.day_list("nationalday","nationalday_getaward-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_nationaldayData))
			return n_code, t_nationaldayData
		end
	end



	local data={
		items=items,
		all_data = t_nationaldayData
	}
	--log.day_list("nationalday","nationalday_getaward-flag-3",ngx.ctx.t_params.uin,t_nationaldayData.total_coupons)
	return t_retCode.n_OK, data

end

--------------------------------------------------------------
-- 说明：国庆任务游园券兑换奖励
-- 返回：n					状态码
--		ts 					描述
this.nationalday_exchange_award = function()
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_nationaldayData = t_user:get_nationalday_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("nationalday","nationalday_exchange_award-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_nationaldayData))
		return n_code, t_nationaldayData
	end
	local items={}
	local s_desc=1
	local _desc=1

	if t_nationaldayData.total_coupons == nil or t_nationaldayData.task == nil then
		return t_retCode.n_NO_DATA, 'is_not_nationalday_data' -- 没有任务数据
	end

	local conf 	= mis_data.t_nationalday.t_conf

	if conf.exchange_award[t_params.task_number] and t_nationaldayData.total_coupons > 0 and
		t_nationaldayData.total_coupons >= conf.exchange_award[t_params.task_number].coupons_cost then
			--如果已经有永久avatar了,阻止兑换
			if t_params.task_number <= 5 then --前五才要判断
				local avatar = mis_bridge.query_user_avatar(t_params.uin)
				if uu.tableNotEmpty(avatar) then
					for k,v in pairs(avatar) do
						if v.ModelID == conf.exchange_award[t_params.task_number].ModelID and v.ExpireTime == -1 then
							return 666, '您已拥有该装扮'
						end
					end
				end

			end
			--

			t_nationaldayData.total_coupons = t_nationaldayData.total_coupons - conf.exchange_award[t_params.task_number].coupons_cost
			table.insert(items,{
				id=conf.exchange_award[t_params.task_number].id,
				num=conf.exchange_award[t_params.task_number].num})
	end


	if uu.tableNotEmpty(items) then
		n_code, _desc = t_user:set_nationalday_data(t_nationaldayData)
		if n_code ~= t_retCode.n_OK then
			log.day_list("nationalday","nationalday_exchange_award-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_nationaldayData))
			return n_code, t_nationaldayData
		end
	end

	n_code, s_desc = mis_data.add_items(t_params.uin, items, mis_config.t_workType.s_NATIONALDAY, 'nationalday_exchange_award')
	if n_code ~= t_retCode.n_OK then
		log.day_list("nationalday","nationalday_exchange_award-flag-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(items))
		return n_code, s_desc
	end

	--埋点数据
	mis_log.remote_pure_day('nationalday', mis_common.table_to_json({
							key = 'exchange';
							ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
							uin = t_params.uin;
							time = uu.now();
							country = t_params.country or 'nil';
							apiid = t_params.apiid or 'nil';
							ver = t_params.ver or 'nil';
							lang = t_params.lang or 'nil';
							bonusid = items;
						}))


	local data={
		items=items,
		all_data = t_nationaldayData
	}
	log.day_list("nationalday","nationalday_exchange_award-flag-3",ngx.ctx.t_params.uin,t_nationaldayData.total_coupons,uu.to_str(items))
	return t_retCode.n_OK, data

end

---｛｛
--------------------------------------------------------------
--[[
 * @description tab中是否包含value
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/15
 * @params
 * @return
 ]]
local function is_include(tab,value)
	for i, v in ipairs(tab) do
		if v==value then
			return true
		end
	end
	return false
end

--[[
 * @description 传入字符串时间和时区，得出对应的时间戳
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/16
 * @params
 * @return
 ]]
local t_m_dayUntilMonth = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}
local t_m_dayUntilMonth4 = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
local t_m_dayOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
local t_m_dayOfMonth4 = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
local function date_to_uninx(s_time, time_zone)
	local t_ = 62136979200 + (tonumber(time_zone) * 3600)
	local n_year, n_month, n_day, n_hour, n_min, n_sec = string_match(s_time, '(%d+)%p(%d+)%p(%d+)%p*%s*(%d*)%p*(%d*)%p*(%d*)')
	n_year = tonumber(n_year) or 0
	n_month = tonumber(n_month) or 0
	n_day = tonumber(n_day) or 0
	n_hour = tonumber(n_hour) or 0
	n_min = tonumber(n_min) or 0
	n_sec = tonumber(n_sec) or 0
	local n_a = n_year - 1
	local n_b = n_a * 365 + math_floor(n_a / 4)
	if n_year % 4 == 0 then
		n_b = n_b + t_m_dayUntilMonth4[n_month]
	else
		n_b = n_b + t_m_dayUntilMonth[n_month]
	end
	n_b = n_b + n_day
	n_b = n_b * 86400 + n_hour * 3600 + n_min * 60 + n_sec
	--return math_max(n_b - (62136979200+(tonumber(time_zone)*3600)), 0)
	return math_max(n_b - t_, 0)
end
--[[
 * @description 传入时间戳和时区，返回对应时区的时间
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/31
 * @param t_time 时间戳
 * @Param timeZone 时区
 * @return 样式：2021-12-31 16:28:06
 ]]
local function unix_to_date(t_time,timeZone)
	return os.date("!%Y-%m-%d %H:%M:%S", t_time + timeZone * 60 * 60) or nil
end
--[[
 * @description doubledan活动，业务前置检测
 *              此处检测配置是否已加载和配置是否为空
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/6
 * @param
 * @return  ｛｛
 				n_OK		 	= 0;							-- ok
				n_SYS_ERR		= 6000001;						-- 系统错误
				n_PARAM_ERR 	= 6000002;						-- 参数错误
				n_AUTH_ERR 		= 6000003;						-- 鉴权错误
				n_NET_ERR		= 6000004;						-- 网络错误
				n_DB_ERR		= 6000005;						-- 数据库错误
				n_OPER_ERR		= 6000006;						-- 用户行为错误
				n_WORK_ERR		= 6000007;						-- 业务错误
				n_NO_DATA		= 6000008;						-- 没有数据
				n_DB_LIMIT		= 100;							-- DB限流
 		｝｝

 ]]

local area_mapping={[704]="VN",[764]="TH",[076]="BR",[484]="MX",[360]="ID",[392]="JP",[156]="TW"}
this.pre_doubledan = function()

	local t_params = ngx.ctx.t_params
	if mis_data.t_doubledan.n_status ~= mis_config.t_workStatus.n_ENABLE then
		log.day_list("doubledan", "pre_doubledan-flag-1", ngx.ctx.t_params.uin)
		return t_retCode.n_OPER_ERR, {msg='doubledan disable'}
	end
	local conf = mis_data.t_doubledan.t_conf
	if conf == nil or conf.tasks == nil then
		log.day_list("doubledan", "pre_doubledan-flag-1-2", ngx.ctx.t_params.uin)
		return t_retCode.n_NO_DATA, {msg='doubledan conf error'}
	end
	--参数检查

	--检查语言
	local langs = mis_uu.split(conf.langs,",")
	if is_include(langs,t_params.lang)==false then
		return t_retCode.n_PARAM_ERR, {msg='lang limited'}
	end
	local area
	--生效地区
	if conf.effective_area~=nil and #conf.effective_area~=0 then
		if t_params.effective_area==nil then
			return t_retCode.n_PARAM_ERR,{msg='effective_area param required'}
		else
			local effective_area ={}
			for area, time_zone in pairs(conf.effective_area) do
				table_insert(effective_area, area)
			end
			if tonumber(t_params.effective_area) ~= nil then
				area = area_mapping[tonumber(t_params.effective_area)]
			else
				area = uu.split(t_params.effective_area, "_")[1]
			end
			if is_include(effective_area, area) == false then
				return t_retCode.n_PARAM_ERR,{msg='out of effective_area'}
			end
		end
	end
	--检查版本
	if t_params.ver==nil then
		return t_retCode.n_PARAM_ERR,{msg='ver param required'}
	end
	local n_ver = mis_common.version_to_number(t_params.ver)
	local version_min=mis_common.version_to_number(conf.version_min)
	local version_max=mis_common.version_to_number(conf.version_max)
	if version_min > n_ver or n_ver > version_max then
		return t_retCode.n_PARAM_ERR,{msg='out of version limit'}
	end

	--检查时间
	--local endTime = times_with_timezone(mis_common.date_to_unix(conf.end_time or '1997-01-01')-8*3600)
	--local startTime = times_with_timezone(mis_common.date_to_unix(conf.start_time or '1997-01-01')-8*3600)
	--local area = uu.split(t_params.effective_area,"_")[1]
	if tonumber(t_params.effective_area) ~= nil then
		area = area_mapping[tonumber(t_params.effective_area)]
	else
		area = uu.split(t_params.effective_area, "_")[1]
	end
	if area == nil or tonumber(conf.effective_area[area]) == nil then
		return t_retCode.n_PARAM_ERR, { msg = 'unknow effective_area' }
	end
	ngx.ctx.t_params.timeZone=conf.effective_area[area]
	local endTime = date_to_uninx(conf.end_time or '1997-01-01',conf.effective_area[area])
	local startTime = date_to_uninx(conf.start_time or '1997-01-01',conf.effective_area[area])
	local n_now = uu.now()
	if n_now < startTime then
		return t_retCode.n_NO_DATA, {msg='doubledan  has not started yet'}
	elseif n_now > endTime then
		--超过数据保留期则清除数据
		if n_now > (endTime + 86400 * tonumber(conf.keep_data_time)) then
			local t_user = mis_data.get_user()
			local n_code, t_doubledanData = t_user:delete_doubledan_data()
			if n_code ~= t_retCode.n_OK then
				log.day_list("doubledan", "pre_doubledan-flag-1", ngx.ctx.t_params.uin, uu.to_str(n_code), uu.to_str(t_doubledanData))
				return t_retCode.n_NO_DATA, {msg='doubledan  has ended'}
			end
		end
		return t_retCode.n_NO_DATA, {msg='doubledan  has ended'}
	end
	--总控开关
	if conf.control_all==0 then
		return t_retCode.n_NO_DATA, {msg='doubledan has ended'}
	end
	--检查客户端
	if conf.terminal[1]~='ALL' then
		local terminal = t_params.terminal
		if terminal == nil then
			return t_retCode.n_PARAM_ERR,{msg= 'terminal param required'}
		elseif is_include(conf.terminal,terminal)==false then
			return t_retCode.n_PARAM_ERR, {msg='terminal limited'}
		end
	end



	--检查apiid
	if conf.apiid~=nil and #conf.apiid>0 then
		if t_params.apiid==nil then
			return t_retCode.n_PARAM_ERR,'apiid param required'
		end
		if is_include(conf.apiid,tonumber(t_params.apiid))==false then
			return t_retCode.n_PARAM_ERR,{msg='out of apiid limit'}
		end
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
--[[
 * @description 基础参数检查
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/8
 * @params
 * @return
 ]]
local function check_base_params(conf)
	local t_params = ngx.ctx.t_params
	local task=conf.tasks[tonumber(t_params.task_number)]
	if task==nil then
		return t_retCode.n_PARAM_ERR,'invalid task_number'
	end

	if task.control == 0 then
		return t_retCode.n_NO_DATA, 'the task has closed'
	end
	return t_retCode.n_OK,''
end

--[[
 * @description  领取任务时判断是否在活动期内
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/6
 * @param task_number 任务编号，样例配置中从1开始
 * @return bool类型，true则在活动期内，可以领取，否则不能领取
 ]]
local function check_doubledan_get_coretime()
	local n_now = uu.now()
	local conf 	= mis_data.t_doubledan.t_conf
	--local flag_endtime = mis_common.date_to_unix(conf.close_time or '1997-01-01')
	local t_params = ngx.ctx.t_params
	local area
	if tonumber(t_params.effective_area)~=nil then
		area=area_mapping[tonumber(t_params.effective_area)]
	else
		area = uu.split(t_params.effective_area,"_")[1]
	end
	--local area = uu.split(t_params.effective_area,"_")[1]
	local flag_endtime = date_to_uninx(conf.close_time or '1997-01-01',conf.effective_area[area])
	log.debug("n_now:"..n_now.." flag_endtime:"..flag_endtime)
	if n_now > flag_endtime then
		log.day_list("doubledan","check_doubledan_get_coretime-flag-1",ngx.ctx.t_params.uin,uu.to_str(flag_endtime),n_now)
		return false
	end
	return true
end

--------------------------------------------------------------
-- 说明：双旦任务触发核心
--要求参数传入task_number
-- 返回：n					状态码
--		ts 					描述
local function task_doubledan_core(conf,t_doubledanData)

	--**************************************************************************--
	--当map_list不为空时，传进的地图ID是否在map_list列表中
	local function in_limit_map(task)
		--map_list为空则认为没有地图限制
		if task.map_list == nil or #task.map_list == 0 then
			return true
		end
		local t_params = ngx.ctx.t_params
		for i, map_id in pairs(task.map_list) do
			if map_id == t_params.map_id then
				return true
			end
		end
		log.debug(t_params.map_id .." is not in map_list")
		return false
	end
	--联机游戏时长,如果五张地图每张地图6分钟也算，这里算的是总的时间
	local function online_play_time(task_data, task)
		log.debug("online_play_time called.")
		uu.var_dump({ conditions = task_data.conditions, task = task })
		if in_limit_map(task) then
			local t_params = ngx.ctx.t_params
			task_data.conditions.online_play_time = task_data.conditions.online_play_time + tonumber(t_params.play_time)
		end
	end
	--连续登录
	local function continue_login_day(task_data, task)
		log.debug("continue_login_day called.")
		uu.var_dump({ conditions = task_data.conditions, task = task })
		task_data.conditions.continue_login_day = task_data.conditions.continue_login_day + 1
	end
	--通过分享卡片进入游戏
	local function enter_by_share_card(task_data, task)
		log.debug("enter_by_share_card called.")
		uu.var_dump({ conditions = task_data.conditions, task = task })
		task_data.conditions.enter_by_share_card = task_data.conditions.enter_by_share_card + 1
	end
	--添加好友
	local function increase_friends(task_data, task)
		log.debug("increase_friends called.")
		uu.var_dump({ conditions = task_data.conditions, task = task })
		task_data.conditions.increase_friends = task_data.conditions.increase_friends + 1
	end

	--这是一个特殊的条件，他是一个复合条件，即完成任务的条件有条件
	--体现在这里是完成该任务需要完成3局，但是玩的时间大于五分钟才算一局
	local function play_online_tuple(task_data, task)
		log.debug("play_online_tuple called.")
		uu.var_dump({ conditions = task_data.conditions, task = task })
		if in_limit_map(task) then
			if task_data.status == 0 then
				--这里要传一个当前局的ID 开局的时候的时间戳，每次上报看看是不是同一局
				local tuple_data = task_data.conditions.play_online_tuple[ngx.ctx.t_params.map_id]
				if tuple_data~=nil then
					local t_params = ngx.ctx.t_params
					--正常上报时play_status为playing，退出时将时间清零
					--if t_params.play_status=='playing' then
					--	tuple_data.duration_of_each_times = tuple_data.duration_of_each_times + 60
					--	if tuple_data.duration_of_each_times >= task.task_conditions.play_online_tuple.duration_of_each_times then
					--		tuple_data.times = tuple_data.times + 1
					--		tuple_data.duration_of_each_times=0
					--	end
					--	if tuple_data.times >= task.task_conditions.play_online_tuple.times then
					--		tuple_data.status=1
					--	end
					--else
					--	tuple_data.duration_of_each_times=0
					--end

					--由客户端定时上报改成用户退出游戏时上报
					if t_params.play_status=='quit' then
						if tonumber(t_params.play_time)>= task.task_conditions.play_online_tuple.duration_of_each_times then
							tuple_data.times = tuple_data.times + 1
						end
						if tuple_data.times >= task.task_conditions.play_online_tuple.times then
							tuple_data.status=1
						end
						local totle_times = 0
						for mapi_id, map_process in pairs(task_data.conditions.play_online_tuple) do
							totle_times = totle_times + map_process.times or 0
						end
						if totle_times >= task.task_conditions.play_online_tuple.times then
							task_data.status=1
						end
					end

				end
			end

		end
	end

	--通过分享任务进入游戏
	local function enter_by_share_mission(task_data, task)
		log.debug("enter_by_share_mission called.")
		uu.var_dump({ conditions = task_data.conditions, task = task })
		task_data.conditions.enter_by_share_mission = task_data.conditions.enter_by_share_mission + 1
	end

	--把任务分享出去
	local function share_mission_out(task_data, task)
		log.debug("share_mission_out called.")
		uu.var_dump({ conditions = task_data.conditions, task = task })
		task_data.conditions.share_mission_out = task_data.conditions.share_mission_out + 1
	end
	--**************************************************************************--



	--是否有任务完成标识符，当有任务完成时即为true
	local flag_qipao = false
	if t_doubledanData.tasks then
		local t_params = ngx.ctx.t_params
		local t_number=tonumber(t_params.task_number)
		local task_type = t_doubledanData.tasks[t_number].task_type
		log.debug('t_number is:'..t_number.."..task_type is:"..task_type)
		for task_number, task_data in pairs(t_doubledanData.tasks) do
			if task_data.task_type == task_type then
				if task_data ~= nil and task_data.status == 0 then

					--任务状态标识符，所有条件都完成即为true
					local status_flag = false

					for i, v in pairs(task_data.conditions) do
						--这里的i即为任务条件的k 以下局部方法都是这里调用

							--在线指定时长
						if i=='online_play_time' then
							online_play_time(task_data, conf.tasks[task_number])
							--登陆
						elseif i=='continue_login_day' then
							continue_login_day(task_data, conf.tasks[task_number])
							--通过分享卡片进入游戏
						elseif i=='enter_by_share_card' then
							enter_by_share_card(task_data, conf.tasks[task_number])
							--增加好友
						elseif i=='increase_friends' then
							increase_friends(task_data, conf.tasks[task_number])
							--打X局（同一张地图超过y分钟算一局）
						elseif i=='play_online_tuple' then
							play_online_tuple(task_data, conf.tasks[task_number])
							--通过分享任务进入游戏
						elseif i == 'enter_by_share_mission' then
							enter_by_share_mission(task_data, conf.tasks[task_number])
							--把任务分享出去
						elseif i == 'share_mission_out' then
							share_mission_out(task_data, conf.tasks[task_number])
						else
							log.debug("unknown func")
						end

						if type(conf.tasks[task_number].task_conditions[i]) == 'number' then
							log.debug("do_num is:"..task_data.conditions[i].." target is:"..conf.tasks[task_number].task_conditions[i])
							if task_data.conditions[i] >= conf.tasks[task_number].task_conditions[i]  then
								status_flag = true
							else
								status_flag = false
							end
						else
							if task_data.status == 1 then
								status_flag = true
							end
						end

					end
					--所有条件都完成，这个时候把任务状态改成已完成，等待领取
					if status_flag then
						task_data.status = mis_config.t_missionStatus.n_DONE
						flag_qipao = true
					end
				else
					if task_data ~= nil and task_data.status == 1 then
						flag_qipao = true
					end
				end

			end
		end


	end

	return t_doubledanData, flag_qipao
end

--------------------------------------------------------------
--[[
 * @description 初始化双旦活动数据
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/6
 * @param conf 双旦活动配置
 * @param n_now 服务器当前时间
 * @return 初始化后的数据
 ]]
local function init_doubledanData(conf,n_now)
	log.debug("len of conf.tasks"..#conf.tasks)
	local t_doubledanData_tasks = {}
	for i = 1, #conf.tasks do
		if conf.tasks[i] then
				--时间范围内还需开关控制打开
				if conf.tasks[i].control == 1 then
					local init_condition = {}
					for k, v in pairs(conf.tasks[i].task_conditions) do
						if type(v) == 'table' then
							if k == 'play_online_tuple' then
								local play_online_tuple = {}
								if conf.tasks[i].map_list and #conf.tasks[i].map_list > 0 then
									for id_index, map_id in pairs(conf.tasks[i].map_list) do
										if play_online_tuple[map_id]==nil then
											play_online_tuple[map_id]={}
										end
										play_online_tuple[map_id].duration_of_each_times = 0
										play_online_tuple[map_id].times = 0
									end
								else
									if play_online_tuple[-999]==nil then
										play_online_tuple[-999]={}
									end
									play_online_tuple[-999].duration_of_each_times = 0
									play_online_tuple[-999].times = 0
								end
								init_condition[k] = play_online_tuple

							end
						elseif type(v) == 'number' then
							init_condition[k] = 0
						else
							init_condition[k] = ''
						end
					end

					--这里即数据库中最终保存的内容
					local tmp = {
						--day_time = n_now, --初次请求数据的时间戳
						task_type = conf.tasks[i].task_type, --任务类型
						task_id = conf.tasks[i].task_id,--任务ID
						conditions = init_condition, --任务达成条件的值
						status = 0 --0：未完成，1：已完成（待领取），2：已领取  |后面重构时把这些常量写进常量池
					}
					--（#t_doubledanData_tasks + 1）为task_number
					t_doubledanData_tasks[#t_doubledanData_tasks + 1] = tmp
				end

		end
	end
	mis_log.debug("++++++++++++++++++++++++++++++++++++++++++++++++++")
	mis_uu.var_dump(t_doubledanData_tasks)
	mis_log.debug("++++++++++++++++++++++++++++++++++++++++++++++++++")
	return t_doubledanData_tasks
end



--------------------------------------------------------------
--[[
 * @description 活动奖励分类添加
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/15
 * @params
 * @return
 ]]
local function add_gifts(gift,t_doubledanData,items)
	for m, n in pairs(gift) do
		--type_id  1为兑换券2为抽奖券3为道具4为卡片
		if n.type_id == 4 then
			if t_doubledanData.card == nil then
				t_doubledanData.card = {}
			end
			if t_doubledanData.card[n.id] == nil then
				t_doubledanData.card[n.id]=0
			end
			t_doubledanData.card[n.id] = t_doubledanData.card[n.id] + n.num
		elseif n.type_id == 3 then
			table_insert(items, { n.id, n.num })
		elseif n.type_id == 2 then
			if t_doubledanData.draw == nil then
				t_doubledanData.draw = {}
			end
			if t_doubledanData.draw[n.id] == nil then
				t_doubledanData.draw[n.id]=0
			end
			t_doubledanData.draw[n.id] = t_doubledanData.draw[n.id] + n.num

		elseif n.type_id == 1 then
			if t_doubledanData.exchange == nil then
				t_doubledanData.exchange = {}
			end
			if t_doubledanData.exchange[n.id] == nil then
				t_doubledanData.exchange[n.id]=0
			end
			t_doubledanData.exchange[n.id] = t_doubledanData.exchange[n.id] + n.num

		else
			log.error("unknown item type_id")
		end
		--table_insert(items, n)
	end
	return t_doubledanData,items
end

--[[
 * @description 请求时跨周期了要重置下数据
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/24
 * @params
 * @return
 ]]
local function re_init_data(t_doubledanData,conf,n_now)
	log.debug("not same day")
	--代表不是同一天
	local items = {}--第二天没领取的要帮忙领
	for k, v in pairs(t_doubledanData.tasks) do
		if v.status == mis_config.t_missionStatus.n_DONE then
			--已经完成但未领取
			for j, k in pairs(conf.tasks) do
				if k.task_id == v.task_id then
					t_doubledanData,items=add_gifts(k.gift,t_doubledanData,items)
				end
			end
		end
	end

	--此时要刷新每日任务
	t_doubledanData.day_time = n_now
	--刷新数据
	t_doubledanData.tasks = init_doubledanData(conf, n_now)
	if t_doubledanData.card==nil then
		t_doubledanData.card={}
	end
	if t_doubledanData.exchange==nil then
		t_doubledanData.exchange={}
	end
	if t_doubledanData.draw==nil then
		t_doubledanData.draw={}
	end

	return t_doubledanData,items
end
--[[
 * @description 获取玩家双旦活动当前状态
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/6
 * @params
 * @return
 ]]
this.doubledan_get_task_status = function()
	local _desc,n_code
	local t_params = ngx.ctx.t_params
	--获取最新配置
	local conf = mis_data.t_doubledan.t_conf

	local t_user = mis_data.get_user()
	local n_code, t_doubledanData = t_user:get_doubledan_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan", "doubledan_get_task_status-flag-1", ngx.ctx.t_params.uin, uu.to_str(n_code), uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, {msg='db request failed'}
	end

	local n_now = uu.now()

	if t_doubledanData==nil then
		t_doubledanData={}
	end

	if t_doubledanData.tasks == nil or #t_doubledanData.tasks ==0  then
		--初始化任务数据的时间
		if t_doubledanData.day_time==nil or t_doubledanData.day_time==0 then
			t_doubledanData.day_time=n_now
		end

		t_doubledanData.tasks = init_doubledanData(conf, n_now)
		if t_doubledanData.card==nil then
			t_doubledanData.card={}
		end
		if t_doubledanData.exchange==nil then
			t_doubledanData.exchange={}
		end
		if t_doubledanData.draw==nil then
			t_doubledanData.draw={}
		end
	end

	log.debug("timeZone is:"..t_params.timeZone)
	local time1 = unix_to_date(n_now, t_params.timeZone)
	local time2 = unix_to_date(t_doubledanData.day_time, t_params.timeZone)
	--年月日不相同
	if uu.split(time1," ")[1]~=uu.split(time2," ")[1] then
		local t_doubledanData_inited, items = re_init_data(t_doubledanData, conf, n_now)
		t_doubledanData=t_doubledanData_inited
		if #items > 0 then
			--调用账号服，把items里的奖励发给用户
			n_code, _desc = mis_data.add_items(t_params.uin, items, mis_config.t_workType.s_doubledan, 'doubledan_getaward')
			if n_code ~= t_retCode.n_OK then
				log.day_list("doubledan","doubledan_get_task_status-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(items))
				return t_retCode.n_WORK_ERR, {msg='call account add_items failed'}
			end
		end

	end

	--这里的比较是否是同一天的方法应该重写，应该改成是否在同一个周期内
	--if uu.compareTimes(n_now, t_doubledanData.day_time) == false then
	--	local t_doubledanData_inited, items = re_init_data(t_doubledanData, conf, n_now)
	--	t_doubledanData=t_doubledanData_inited
	--	if #items > 0 then
	--		--调用账号服，把items里的奖励发给用户
	--		n_code, _desc = mis_data.add_items(t_params.uin, items, mis_config.t_workType.s_doubledan, 'doubledan_getaward')
	--		if n_code ~= t_retCode.n_OK then
	--			log.day_list("doubledan","doubledan_get_task_status-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(items))
	--			return t_retCode.n_WORK_ERR, {msg='call account add_items failed'}
	--		end
	--	end
	--
	--end
	log.debug("this is t_doubledanData:")
	mis_uu.var_dump(t_doubledanData)

	n_code, _desc = t_user:set_doubledan_data(t_doubledanData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan", "doubledan_get_task_status-flag-2", ngx.ctx.t_params.uin, uu.to_str(n_code), uu.to_str(_desc), uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, {msg='db update failed'}
	end
	return t_retCode.n_OK,  t_doubledanData.tasks
end

--------------------------------------------------------------

--[[
 * @description 双旦任务触发
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/6
 * @params
 * @return
 ]]
this.doubledan_task_event = function()
	local t_params = ngx.ctx.t_params
	--获取最新配置
	local conf = mis_data.t_doubledan.t_conf
	--参数校验
	local n_code,_desc=check_base_params(conf)
	if n_code~= t_retCode.n_OK then
		return n_code,{msg=_desc}
	end
	--9.地图体验次数且地图体验时长
	--此时要检查是否传了play_status参数
	if conf.tasks[tonumber(t_params.task_number)].task_type==9 then
		if t_params.play_status==nil then
			return t_retCode.n_PARAM_ERR,{msg='play_status param required'}
		end
	end
	--此时要检查是否传了map_id参数
	local _t=conf.tasks[tonumber(t_params.task_number)]
	if _t.task_type==9 or _t.task_type==2 then
		if t_params.map_id==nil then
			return t_retCode.n_PARAM_ERR,{msg='map_id param required'}
		end
	end

	local t_user = mis_data.get_user()
	local n_code, t_doubledanData = t_user:get_doubledan_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan","doubledan_task_event-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, {msg='db request failed'}
	end

	if t_doubledanData==nil then
		t_doubledanData={}
	end
	local n_now = uu.now()

	if t_doubledanData.tasks == nil or #t_doubledanData.tasks == 0 then
		if t_doubledanData.day_time == nil or t_doubledanData.day_time == 0 then
			t_doubledanData.day_time = n_now
		end
		t_doubledanData.tasks = init_doubledanData(conf, n_now)
		if t_doubledanData.card==nil then
			t_doubledanData.card={}
		end
		if t_doubledanData.exchange==nil then
			t_doubledanData.exchange={}
		end
		if t_doubledanData.draw==nil then
			t_doubledanData.draw={}
		end
	end
	log.debug("timeZone is:"..t_params.timeZone)
	local time1 = unix_to_date(n_now, t_params.timeZone)
	local time2 = unix_to_date(t_doubledanData.day_time, t_params.timeZone)
	--年月日不相同
	if uu.split(time1," ")[1]~=uu.split(time2," ")[1] then
		local t_doubledanData_inited, items = re_init_data(t_doubledanData, conf, n_now)
		t_doubledanData=t_doubledanData_inited
		if #items > 0 then
			--调用账号服，把items里的奖励发给用户
			n_code, _desc = mis_data.add_items(t_params.uin, items, mis_config.t_workType.s_doubledan, 'doubledan_getaward')
			if n_code ~= t_retCode.n_OK then
				log.day_list("doubledan","doubledan_get_task_status-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(items))
				return t_retCode.n_WORK_ERR, {msg='call account add_items failed'}
			end
		end

	end
	--这里的比较是否是同一天的方法应该重写，应该改成是否在同一个周期内
	--if uu.compareTimes(n_now, t_doubledanData.day_time) == false then
	--	local t_doubledanData_inited, items = re_init_data(t_doubledanData, conf, n_now)
	--	t_doubledanData=t_doubledanData_inited
	--	if #items > 0 then
	--		--调用账号服，把items里的奖励发给用户
	--		n_code, _desc = mis_data.add_items(t_params.uin, items, mis_config.t_workType.s_doubledan, 'doubledan_getaward')
	--		if n_code ~= t_retCode.n_OK then
	--			log.day_list("doubledan","doubledan_get_task_status-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(items))
	--			return t_retCode.n_WORK_ERR, {msg='call account add_items failed'}
	--		end
	--	end
	--
	--end

	local t_doubledanData, flag_qipao = task_doubledan_core(conf,t_doubledanData)
	n_code, _desc = t_user:set_doubledan_data(t_doubledanData)

	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan","doubledan_task_event-flag-4",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, {msg='db update failed'}
	end

	return t_retCode.n_OK, {flag_qipao = flag_qipao or false,data = t_doubledanData.tasks[tonumber(t_params.task_number)]}

end

--------------------------------------------------------------
--[[
 * @description  双旦任务领取奖励
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/6
 * @params
 * @return
 ]]
this.doubledan_getaward = function()
	local t_params  		= ngx.ctx.t_params
	--获取最新配置
	local conf = mis_data.t_doubledan.t_conf
	local n_code,_desc=check_base_params(conf)
	if n_code~= t_retCode.n_OK then
		return n_code,{msg=_desc}
	end
	local t_user = mis_data.get_user()
	local n_code, t_doubledanData = t_user:get_doubledan_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan","doubledan_getaward-flag-1",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, {msg='db request failed'}
	end
	local items={}
	local _desc = 1

	if t_doubledanData==nil then
		return t_retCode.n_NO_DATA, {msg='Please check whether the task is received'}
	end
	local t_number=tonumber(t_params.task_number)
	if t_doubledanData.tasks and t_doubledanData.tasks[t_number] then
		--过期不候 指定时间内才可以领
		if check_doubledan_get_coretime() == false then
			log.day_list("doubledan","doubledan_getaward-flag-1-2",ngx.ctx.t_params.uin)
			return t_retCode.n_NO_DATA, {msg='is_not_doubledan_task_time'} -- 不在任务期
		end
		--领取的任务完成了才可以
		if t_doubledanData.tasks[t_number].status == mis_config.t_missionStatus.n_DONE then
			--更新领取状态
			t_doubledanData.tasks[t_number].status = mis_config.t_missionStatus.n_PICKED

			t_doubledanData,items=add_gifts(conf.tasks[t_number].gift,t_doubledanData,items)



			--数据写回数据库并通知账号服发货
			if uu.tableNotEmpty(items) then
--[[				--数据写回数据库
				n_code, _desc = t_user:set_doubledan_data(t_doubledanData)
				if n_code ~= t_retCode.n_OK then
					log.day_list("doubledan","doubledan_getaward-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_doubledanData))
					return t_retCode.n_DB_ERR, {msg='db update failed'}
				end]]
				log.debug("call account add_items!")
				--通知账号服发货
				log.debug('t_workType:'..mis_config.t_workType.s_doubledan)
				n_code, _desc = mis_data.add_items(t_params.uin, conf.tasks[t_number].gift, mis_config.t_workType.s_doubledan, 'doubledan_getaward')
				if n_code ~= t_retCode.n_OK then
					log.day_list("doubledan","doubledan_getaward-flag-1-2",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(items))
					return t_retCode.n_WORK_ERR, {msg='call account add_items failed'}
				end
			end

			n_code, _desc = t_user:set_doubledan_data(t_doubledanData)

			if n_code ~= t_retCode.n_OK then
				log.day_list("doubledan","doubledan_task_event-flag-4",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_doubledanData))
				return t_retCode.n_DB_ERR, {msg='db update failed'}
			end
		elseif t_doubledanData.tasks[t_number].status == mis_config.t_missionStatus.n_PICKED then
			return t_retCode.n_NO_DATA,{msg='reward received'}
		else
			return t_retCode.n_NO_DATA,{msg='please complete the task first'}
		end
	else
		return t_retCode.n_PARAM_ERR, {msg='doesn`t exist task_number:'..t_number}
	end

	local data = {
		items = conf.tasks[t_number].gift,
		task_data = t_doubledanData.tasks[t_number]
	}
	return t_retCode.n_OK, data

end

--------------------------------------------------------------
--[[
 * @description  双旦任务列表
 * @author  yuhao <yuhao@mini1.cn>
 * @date 2021/12/6
 * @params
 * @return
 ]]
this.doubledan_get_task_list = function()
	--获取最新配置
	local conf = mis_data.t_doubledan.t_conf
	--local endTime = mis_common.date_to_unix(conf.end_time or '1997-01-01')
	--local startTime = mis_common.date_to_unix(conf.start_time or '1997-01-01')
	--local endTime = times_with_timezone(mis_common.date_to_unix(conf.end_time or '1997-01-01')-8*3600)
	--local startTime = times_with_timezone(mis_common.date_to_unix(conf.start_time or '1997-01-01')-8*3600)
	local t_params  		= ngx.ctx.t_params
	--local area = uu.split(t_params.effective_area,"_")[1]
	local area
	if tonumber(t_params.effective_area)~=nil then
		area=area_mapping[tonumber(t_params.effective_area)]
	else
		area = uu.split(t_params.effective_area,"_")[1]
	end
	local endTime = date_to_uninx(conf.end_time or '1997-01-01',conf.effective_area[area])
	local startTime = date_to_uninx(conf.start_time or '1997-01-01',conf.effective_area[area])
	local n_now = uu.now()

	if n_now<startTime or n_now>endTime then
		return t_retCode.n_OK, {}
	end
	return t_retCode.n_OK, conf.tasks


end

--------------------------------------------------------------
-- 说明：双旦任务游园券兑换奖励
-- 返回：n					状态码
--		ts 					描述
this.doubledan_exchange_award = function()
	local t_params  		= ngx.ctx.t_params

	--消耗类型 exchange 为兑换券 draw为抽奖券
	local cost_types = t_params.cost_types
	--消耗数量
	local cost_num = t_params.nums
	--消耗的物品的ID
	local cost_id =t_params.ids

	if cost_types == nil then
		return t_retCode.n_PARAM_ERR, 'cost_types param required'
	end
	if cost_num ==nil then
		return t_retCode.n_PARAM_ERR, 'nums param required'
	end

	if cost_id == nil then
		return t_retCode.n_PARAM_ERR, 'ids param required'
	end

	local  ids = mis_uu.split(cost_id,",")
	local nums = mis_uu.split(cost_num, ",")
	local types = mis_uu.split(cost_types, ",")
	local t_user = mis_data.get_user()
	local n_code, t_doubledanData = t_user:get_doubledan_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan", "doubledan_exchange_award-flag-1", ngx.ctx.t_params.uin, uu.to_str(n_code), uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, { msg = 'db request failed' }
	end


	--兑换
	for i, id in pairs(ids) do
		local cost_type = types[i]
		if cost_type == 'exchange' or cost_type == "draw" or cost_type == "card" then
			local num = tonumber(nums[i])
			if num < 0 then
				return t_retCode.n_PARAM_ERR, 'nums param invalid'
			end

			local int_id = tonumber(id)
			if t_doubledanData[cost_type] == nil or
					t_doubledanData[cost_type][int_id] == nil or
					tonumber(t_doubledanData[cost_type][int_id]) < num then
				return t_retCode.n_NO_DATA, 'balance not enough'
			end

			t_doubledanData[cost_type][int_id] = tonumber(t_doubledanData[cost_type][int_id]) - num
		else
			return t_retCode.n_PARAM_ERR, 'invalid cost_type'
		end
	end

	local n_code, _desc = t_user:set_doubledan_data(t_doubledanData)

	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan","doubledan_exchange_award-flag-4",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, {msg='db update failed'}
	end

	return t_retCode.n_OK,t_doubledanData.exchange,t_doubledanData.draw,t_doubledanData.card
end



--------------------------------------------------------------
-- 说明：双旦任务 获取兑换券、抽奖券、卡片的数量
-- 返回：n					状态码
--		ts 					描述
this.doubledan_get_balance = function()
	local t_user = mis_data.get_user()
	local n_code, t_doubledanData = t_user:get_doubledan_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan", "doubledan_get_balance-flag-1", ngx.ctx.t_params.uin, uu.to_str(n_code), uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, { msg = 'db request failed' }
	end

	return t_retCode.n_OK, {
		exchange = t_doubledanData['exchange'] ,
		draw = t_doubledanData['draw'] ,
		card = t_doubledanData['card']
	}

end

--------------------------------------------------------------
-- 说明：双旦任务 添加卡片
-- 返回：n					状态码
--		ts 					描述
this.doubledan_add_cards = function()
	local t_params  		= ngx.ctx.t_params

	if t_params.ids == nil then
		return t_retCode.n_PARAM_ERR, 'ids param required'
	end
	if t_params.nums ==nil then
		return t_retCode.n_PARAM_ERR, 'nums param required'
	end

	local ids = mis_uu.split(t_params.ids,",")
	local nums=mis_uu.split(t_params.nums,",")
	local gifts={}

	for i, v in pairs(ids) do
		if tonumber(v)==nil or tonumber(nums[i])==nil then
			return t_retCode.n_PARAM_ERR, 'invalid ids or nums'
		end
		if tonumber(nums[i]) < 0 then
			return t_retCode.n_PARAM_ERR, 'nums param invalid'
		end
		table_insert(gifts,{id=tonumber(v),num=tonumber(nums[i]),type_id=4})
	end

	local t_user = mis_data.get_user()
	local n_code, t_doubledanData = t_user:get_doubledan_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan", "doubledan_get_balance-flag-1", ngx.ctx.t_params.uin, uu.to_str(n_code), uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, { msg = 'db request failed' }
	end


	local t_doubledanData,items=add_gifts(gifts,t_doubledanData,nil)
	local n_code, _desc = t_user:set_doubledan_data(t_doubledanData)

	if n_code ~= t_retCode.n_OK then
		log.day_list("doubledan","doubledan_get_balance-flag-4",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(_desc),uu.to_str(t_doubledanData))
		return t_retCode.n_DB_ERR, {msg='db update failed'}
	end

	return t_retCode.n_OK,t_doubledanData['card']

end

---｝｝

--------------------------------------------------------------
-- 说明：成长守护 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_growthguard = function()
	if mis_data.t_growthguard.n_status ~= mis_config.t_workStatus.n_ENABLE then
		log.day_list("growthguard","pre_growthguard","conf disable", ngx.ctx.t_params.uin, uu.to_str(mis_data.t_growthguard.n_status))
		return t_retCode.n_OPER_ERR, 'growthguard disable'
	end
	local conf 	= mis_data.t_growthguard.t_conf
	if conf == nil then
		log.day_list("growthguard","pre_growthguard","conf nil",ngx.ctx.t_params.uin)
		return t_retCode.n_NO_DATA, 'growthguard conf error'
	end
	return t_retCode.n_OK
end


--------------------------------------------------------------
-- 说明：成长守护 获取状态
-- 返回：n					状态码
--		ts 					描述
local get_growthguard_status = function(t_user)
	-- 参与状态：0未开启，1已开启，2可领奖
	-- 助力状态：0不可助力，1可助力, 2已助力
	local join_status, sign_status
	local n_weekday
	local n_now = mis_data.offset_now()

	local n_code, t_growthguardData = t_user:get_growthguard_data(true)
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_status","get user data error",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_growthguardData))
		return n_code, t_growthguardData
	end

	-- 判断是否已开启助力
	if not t_growthguardData.join_time then
		join_status = 0
	elseif (n_now - t_growthguardData.join_time) < n_WEEK_SEC then
		join_status = 1
	else
		join_status = 2
	end

	-- 助力状态（只能在周五、六、日助力，一天仅一次）
	n_weekday = tonumber(os_date("%w", n_now))
	if (n_weekday ~= 5 and n_weekday ~= 6 and n_weekday ~= 0)
	or (t_growthguardData.sign_count or 0) >= 3
	then
		sign_status = 0
	else
		-- 判断今天是否已助力
		if t_growthguardData.sign_time
		and os_date("%Y%m%d", t_growthguardData.sign_time) == os_date("%Y%m%d", n_now) then
			sign_status = 2
		else
			sign_status = 1
		end
	end

	-- 回复数据
	local t_resp = {
		join_status = join_status,
		sign_status = sign_status,
		sign_count = t_growthguardData.sign_count or 0,
		finish_time = t_growthguardData.join_time and (t_growthguardData.join_time + n_WEEK_SEC) or 0
	}

	log.day_list("growthguard","growthguard_status","ok",ngx.ctx.t_params.uin,uu.to_str(n_weekday),uu.to_str(t_growthguardData),uu.to_str(t_resp))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：成长守护 状态
-- 返回：n					状态码
--		ts 					描述
this.growthguard_status = function()
	-- 参与状态：0未开启，1已开启，2可领奖
	-- 助力状态：0不可助力，1可助力, 2已助力
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	return get_growthguard_status(t_user)
end

--------------------------------------------------------------
-- 说明：成长守护 开启
-- 返回：n					状态码
--		ts 					描述
this.growthguard_join = function()
	local t_params  		= ngx.ctx.t_params

	local n_code, s_desc, t_growthguardData, t_status
	local t_user = mis_data.get_user()

	n_code, t_growthguardData = t_user:get_growthguard_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_join","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_growthguardData))
		return n_code, t_growthguardData
	end

	-- 判断是否已开启助力
	if t_growthguardData.join_time then
		log.day_list("growthguard","growthguard_join","already join",t_params.uin)
		return t_retCode.n_OPER_ERR, "already join"
	end

	t_growthguardData.join_time = mis_data.offset_now()

	n_code, s_desc = t_user:set_growthguard_data(t_growthguardData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard", "growthguard_join", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	n_code, t_status = get_growthguard_status(t_user)
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_join","get_growthguard_status error",t_params.uin,uu.to_str(n_code),uu.to_str(t_status))
		return n_code, s_desc
	end

	return t_retCode.n_OK, t_status
end

--------------------------------------------------------------
-- 说明：成长守护 助力
-- 返回：n					状态码
--		ts 					描述
this.growthguard_signup = function()
	local t_params  		= ngx.ctx.t_params

	local n_code, s_desc, t_growthguardData, t_status
	local t_user = mis_data.get_user()
	local n_weekday
	local n_now = mis_data.offset_now()

	n_code, t_growthguardData = t_user:get_growthguard_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_signup","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_growthguardData))
		return n_code, t_growthguardData
	end

	-- 只能在周五、六、日助力
	n_weekday = tonumber(os_date("%w", n_now))
	if n_weekday ~= 5 and n_weekday ~= 6 and n_weekday ~= 0 then
		log.day_list("growthguard","growthguard_signup","signup day error",t_params.uin, n_weekday)
		return t_retCode.n_OPER_ERR, "signup day error"
	end

	-- 判断是否已开启助力
	if not t_growthguardData.join_time
	or (n_now - t_growthguardData.join_time) > n_WEEK_SEC then
		log.day_list("growthguard","growthguard_signup","not join plan",t_params.uin)
		return t_retCode.n_OPER_ERR, "not join plan"
	end

	-- 判断今天是否已助力
	if t_growthguardData.sign_time
	and os_date("%Y%m%d", t_growthguardData.sign_time) == os_date("%Y%m%d", n_now) then
		log.day_list("growthguard","growthguard_signup","already signup today",t_params.uin)
		return t_retCode.n_OPER_ERR, "already signup today"
	end

	-- 记录助力时间
	t_growthguardData.sign_time = n_now
	t_growthguardData.sign_count = (t_growthguardData.sign_count or 0) + 1

	n_code, s_desc = t_user:set_growthguard_data(t_growthguardData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard", "growthguard_signup", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	n_code, t_status = get_growthguard_status(t_user)
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_signup","get_growthguard_status error",t_params.uin,uu.to_str(n_code),uu.to_str(t_status))
		return n_code, s_desc
	end

	log.day_list("growthguard","growthguard_signup","ok",t_params.uin,uu.to_str(t_status), uu.to_str(t_growthguardData))

	return t_retCode.n_OK, t_status
end

--------------------------------------------------------------
-- 说明：成长守护 领奖
-- 返回：n					状态码
--		ts 					描述
this.growthguard_getaward = function()
	-- 参与状态：0未开启，1已开启，2可领奖
	-- 助力状态：0不可助力，1可助力, 2已助力
	local t_params  		= ngx.ctx.t_params

	local n_code, s_desc, t_growthguardData, n_award_idx
	local t_user = mis_data.get_user()
	local t_conf, t_mission, t_award, t_status

	n_code, t_growthguardData = t_user:get_growthguard_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_getaward","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_growthguardData))
		return n_code, t_growthguardData
	end

	-- 判断是否已开启助力
	if not t_growthguardData.join_time then
		log.day_list("growthguard","not join plan",t_params.uin)
		return t_retCode.n_OPER_ERR, "not join plan"
	end

	-- 判断是否到达领奖时间（5秒容错）
	local dt = mis_data.offset_now() - t_growthguardData.join_time - n_WEEK_SEC
	if dt < -5 then
		log.day_list("growthguard","growthguard_getaward","not award time",t_params.uin,uu.to_str(t_growthguardData.join_time + n_WEEK_SEC))
		return t_retCode.n_OPER_ERR, "not award time"
	end

	-- 奖励索引
	n_award_idx = (t_growthguardData.sign_count or 0) + 1

	-- 刷新助力
	t_growthguardData.join_time = mis_data.offset_now()
	t_growthguardData.sign_count = 0
	t_growthguardData.sign_time = 0

	n_code, s_desc = t_user:set_growthguard_data(t_growthguardData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard" ,"growthguard_getaward", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- 发奖
	t_conf 	= mis_data.t_growthguard.t_conf
	if t_conf == nil then
		log.day_list("growthguard","growthguard_getaward","conf nil",t_params.uin)
		return t_retCode.n_NO_DATA, 'growthguard conf error'
	end

	t_mission = t_conf.mission
	if not t_mission[n_award_idx] or type(t_mission[n_award_idx].bonus) ~= "table" then
		log.day_list("growthguard","growthguard_getaward","award nil",t_params.uin, n_award_idx, uu.to_str(t_mission[n_award_idx]), uu.to_str(t_mission))
		return t_retCode.n_NO_DATA, 'growthguard award nil'
	end

	t_award = {}
	for i = 1, #t_mission[n_award_idx].bonus do
		table_insert(t_award, {
			id = t_mission[n_award_idx].bonus[i].itemId,
			num = t_mission[n_award_idx].bonus[i].num,
		})
	end

	n_code, s_desc = mis_data.add_items(t_params.uin, t_award, mis_config.t_workType.s_GROWTHGUARD, 'growthguard_getaward')
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_getaward","add_items error",t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(t_award))
		return n_code, s_desc
	end

	n_code, t_status = get_growthguard_status(t_user)
	if n_code ~= t_retCode.n_OK then
		log.day_list("growthguard","growthguard_getaward","get_growthguard_status error",t_params.uin,uu.to_str(n_code),uu.to_str(t_status))
		return n_code, s_desc
	end

	local t_resp = {
		items = t_award,
		status = t_status
	}

	log.day_list("growthguard","growthguard_getaward","ok",t_params.uin,uu.to_str(t_award))

	--埋点数据
	mis_log.remote_pure_day('growthguard', mis_common.table_to_json({
		key = 'guardian2021_receive';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = mis_data.offset_now();
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		bonus = n_award_idx;
	}))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：获取角色分享码
-- 返回：n					状态码
--		ts 					描述
this.get_share_code = function()
	local t_params = ngx.ctx.t_params
	local code = ngx.md5(t_params.uin)
	return t_retCode.n_OK, code
end
--------------------------------------------------------------
-- 说明：获取分享活动配置json格式，给h5用
-- 返回：n					状态码
--		ts 					描述
this.get_share_conf = function()
	return t_retCode.n_OK,  mis_data.t_share.s_conf_json
end
--------------------------------------------------------------
-- 说明：.客户端上报事件
-- 参数：share_uin			分享码所有者迷你号
--		code				分享码
--		id					活动id
-- 返回：n					状态码
--		ts 					描述
this.share_click = function()
	local ret={}
	local t_shareData, t_subData, t_user,n_code,_desc
	local t_params = ngx.ctx.t_params
	local n_id = t_params.id
	local t_shareConf = mis_data.t_share.t_conf[n_id]
	t_user = mis_data.get_user(t_params.share_uin)
	n_code, t_shareData = t_user:get_share_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_shareData
	end
	t_subData = t_shareData[n_id]
	--是否已经完成
	local n_totalscore=0
	t_subData.score = t_subData.score or 0
	if not t_shareConf then
		mis_log.day('share', 'param error task_id:' .. n_id)
		return t_retCode.n_PARAM_ERR,"param error"
	end
	for _,v in pairs(t_shareConf.t_bonus) do
		n_totalscore = n_totalscore + v.n_score
	end
	if t_subData.score >=  n_totalscore then
		return t_retCode.n_OK, "already finish "..t_subData.score
	end

	--检验分享码
	local code = ngx.md5(t_params.share_uin)
	if t_params.code ~= code then
		mis_log.day('share', 'MD5 code failed')
		return t_retCode.n_SYS_ERR,"code failed"
	end
	--是否是自己
	if tonumber(t_params.share_uin) == tonumber(t_params.uin) then
		mis_log.day('share', 'share to myself fail')
		return t_retCode.n_SYS_ERR,"share to myself"
	end
	--是否重复
	t_subData.share_uin_list = t_subData.share_uin_list or {}
	t_subData.device_list = t_subData.device_list or {}
	if t_subData.share_uin_list[t_params.uin] then
		mis_log.day('share', 'already share:'..t_params.uin)
		return t_retCode.n_OK,"already share"
	end
	t_subData.share_uin_list[t_params.uin] = 1
	--t_subData.device_list[t_params.device_id]=1

	--判断新老用户
	local t_click_user = mis_data.get_user(t_params.uin)
	n_code, _desc = t_click_user:get_user_basic()
	if n_code == t_retCode.n_NO_DATA then
		--新用户才校验device_id,避免一个设备恶意注册
		if not t_subData.device_list[t_params.device_id] then
			t_subData.score = t_subData.score+t_shareConf.n_new_user or 1
			t_subData.device_list[t_params.device_id]=1
			ret="new user "
		else
			ret="device_id repeat: "..t_params.device_id
		end
	elseif n_code == t_retCode.n_OK then
		if _desc.ture_last_login_time  then
			local n_now = ngx.time()
			ret="old user fail, login time:".._desc.ture_last_login_time.."now time:"..n_now
			local n_min_time = 24*60*60* t_shareConf.n_old_user_offline
			mis_log.debug("n_min_time:"..n_min_time.." day:"..t_shareConf.n_old_user_offline)
			if n_now-tonumber(_desc.ture_last_login_time) >= n_min_time then
				t_subData.score = t_subData.score+t_shareConf.n_old_user or 1
				ret="old user success, login time:".._desc.ture_last_login_time.."now time:"..n_now
			end
		else
			if not t_subData.device_list[t_params.device_id] then
				t_subData.score = t_subData.score+t_shareConf.n_new_user or 1
				t_subData.device_list[t_params.device_id]=1
				ret="new user no login time "
			else
				ret="device_id repeat: "..t_params.device_id
			end
		end

	end

	n_code, _desc = t_user:set_share_data(t_shareData)
	if n_code ~= t_retCode.n_OK then
		return n_code, _desc
	end

	mis_log.day('share', 'onclick share_uin|' .. t_params.share_uin..'| click_uin |'..t_params.uin .. ' result:' .. ret)
	return t_retCode.n_OK, ret
end
--------------------------------------------------------------
-- 说明：.任务进度查看
-- 返回：n					状态码
--		ts 					描述
this.get_share_status = function()
	local t_params = ngx.ctx.t_params
	local b_update
	local n_now, n_id, n_code = ngx.time(), t_params.id
	local s_desc
	local t_, t_ret, t_shareData, t_subData, t_user
	local t_shareConf = mis_data.t_share.t_conf

	t_user = mis_data.get_user()
	n_code, t_shareData = t_user:get_share_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_shareData
	end
	t_subData = t_shareData[n_id]

	-- 数据清理
	-- 清理过期活动
	for n_, t_ in pairs(t_shareData) do
		-- 如果不是当前id，并且（配置不存在或者时间不符合）
		if n_ ~= n_id and (not t_shareConf[n_] or (n_now < t_shareConf[n_].n_startTime or t_shareConf[n_].n_endTime < n_now)) then
			t_shareData[n_] = nil
			mis_log.debug("miss del:"..n_)
			b_update = true
		end
	end

	if b_update then
		n_code, s_desc = t_user:set_share_data(t_shareData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	t_ret = {
		status = t_subData.status;
		score = t_subData.score or 0;
		bonus = t_subData.bonus;
		share_list= t_subData.share_uin_list or {};
	}

	return t_retCode.n_OK, t_ret
end
--------------------------------------------------------------
-- 说明：任务奖励领取
-- 返回：n					状态码
--		ts 					描述
this.share_finish = function()
	local ret ={}
	local t_params = ngx.ctx.t_params
	local n_id = t_params.id
	local t_shareConf = mis_data.t_share.t_conf[n_id]
	local t_user = mis_data.get_user()
	local n_code, t_shareData = t_user:get_share_data(n_id)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_shareData
	end
	local t_subData = t_shareData[n_id]
	if not t_shareConf then
		return t_retCode.n_PARAM_ERR,"param error"
	end

	local n_bonusId =  t_params.bonusId
	local s_items, s_desc
	local t_bonusConf = t_shareConf.t_bonus[n_bonusId]
	if not t_bonusConf then
		return t_retCode.n_PARAM_ERR,"param error"
	end

	--是否积分满足
	if not t_subData.score or t_subData.score < t_bonusConf.n_score then
		return t_retCode.n_OPER_ERR, 'insufficient score'
	end

	--是否已经领取
	if not t_subData.bonus then t_subData.bonus = {} end
	if t_subData.bonus[n_bonusId] then
		return t_retCode.n_OPER_ERR, 'already picked'
	end

	-- 发送道具
	--[[
	n_code, s_desc, s_items = mis_bridge.add_items(t_params.uin, t_bonusConf.t_data, mis_config.t_workType.s_SHARE, 'share_get_bonus')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('share', 'add_items_failed|' .. t_params.uin .. '|' .. n_bonusId .. '|' .. s_items)
		return n_code, s_desc
	end
	]]
	n_code, s_desc = mis_bridge.send_email(t_params.uin, t_bonusConf.s_title,
			t_shareConf.s_body, t_shareConf.n_last, t_bonusConf.t_data)
	if n_code ~= t_retCode.n_OK then
		mis_log.day('share',"send mail fail:"..t_params.uin.." bonusId:"..n_bonusId.." desc:"..s_desc)
		return n_code, s_desc
	end

	t_subData.bonus[n_bonusId] = 1

	n_code, s_desc = t_user:set_share_data(t_shareData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end


	mis_log.day('share', mis_common.table_to_json({
		key = 'bonus';
		activity_id = n_id;
		uin = t_params.uin;
		bonus = t_bonusConf.t_data;
		need_score = t_bonusConf.n_score;
		channel = t_params.apiid or 'null';
		version = t_params.ver or 'null';
		country = t_params.country or 'null';
		language = t_params.lang or 'null';
		ts = ngx.time();
		ip = t_params.s_remoteAddr;
	}))

	return t_retCode.n_OK, ret
end

--------------------------------------------------------------
-- 说明：周末好礼 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_weekend_gift = function()
	local t_params = ngx.ctx.t_params

	--现网屏蔽先
	-- if mis_config.n_debug ~= 1 then
	-- 	return t_retCode.n_OPER_ERR, 'weekend_gift disable2'
	-- end

	local n_now = mis_data.weekend_gift_now()
	local t_conf = mis_data.t_weekend_gift
	if t_conf.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'weekend_gift disable'
	end
	if t_conf.t_conf.n_startTime and n_now < t_conf.t_conf.n_startTime then
		return t_retCode.n_OPER_ERR, 'weekend_gift out of time'
	end
	if t_conf.t_conf.n_endTime and t_conf.t_conf.n_endTime < n_now then
		return t_retCode.n_OPER_ERR, 'weekend_gift out of time'
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：周末好礼 获取状态
-- 返回：n					状态码
--		ts 					描述
local get_weekend_gift_status = function(t_user)
	-- 参与状态：0未开启，1已开启
	local n_rotate_count, n_subscribe_award, t_rotate_award_record
	local n_weekday, n_week
	local n_now = mis_data.weekend_gift_now()
	local t_userDataV2

	local n_code, t_weekendGiftData = t_user:get_weekend_gift_data(true)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","get_weekend_gift_status","get user data error",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_weekendGiftData))
		return n_code, t_weekendGiftData
	end

	-- 判断本周是否已领取订阅奖励（1可领，0不可领）
	if not t_weekendGiftData.subscribe_reward_time
	or os_date("%Y%W", n_now) ~= os_date("%Y%W", t_weekendGiftData.subscribe_reward_time) then
		n_subscribe_award = 0
	else
		n_subscribe_award = 1
		n_code, t_userDataV2 = t_user:get_share_mission_data(mis_config.t_workType.s_WEEKEND_GIFT_V2)
		if n_code ~= t_retCode.n_OK then
			log.day_list("weekend_gift","get_weekend_gift_status_v2","get user data error",t_user.n_uin,uu.to_str(n_code),uu.to_str(t_userDataV2))
		else
			if (t_userDataV2.rotate_level or 0) ~= 0 then
				n_subscribe_award = 0
			end
		end
	end

	-- log.day_list("weekend_gift","get_weekend_gift_status","status",ngx.ctx.t_params.uin,n_now,uu.to_str(t_weekendGiftData))

	-- 判断本周活动期间是否已登录过
	if not t_weekendGiftData.rotate_count
	or not t_weekendGiftData.last_login_time
	or os_date("%Y%W", n_now) ~= os_date("%Y%W", t_weekendGiftData.last_login_time) then
		n_rotate_count = 0
		t_rotate_award_record = {}
	else
		n_rotate_count = t_weekendGiftData.rotate_count
		t_rotate_award_record = {}
		if t_weekendGiftData.rotate_record then
			for k in pairs(t_weekendGiftData.rotate_record) do
				table_insert(t_rotate_award_record, k)
			end
		end
	end

	-- 回复数据
	local t_resp = {
		subscribe_status = t_weekendGiftData.subscribe_status or 0,
		subscribe_award = n_subscribe_award,
		rotate_count = n_rotate_count,
		rotate_award_record = t_rotate_award_record,
	}

	-- log.day_list("weekend_gift","get_weekend_gift_status","ok",ngx.ctx.t_params.uin,uu.to_str(n_weekday),uu.to_str(t_weekendGiftData),uu.to_str(t_resp))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：周末好礼 获取奖池
-- 返回：n					状态码
--		ts 					描述
local get_weekend_gift_award_pool = function()
	local t_conf, t_award_pool
	local n_now = mis_data.weekend_gift_now()
	local n_week

	-- 配置
	t_conf 	= mis_data.t_weekend_gift.t_conf

	-- log.day_list("weekend_gift","get_weekend_gift_award_pool","conf",uu.to_str(mis_data.t_weekend_gift))

	-- 生成奖池（每周奖池不一样）
	n_week = tonumber(os_date("%W", n_now))
	math_randomseed(n_week)
	t_award_pool = {}
	for k, v in ipairs(t_conf.t_login_award) do
		if #v > 0 then
			t_award_pool[k] = v[math_random(1, #v)]
		end
	end

	-- 恢复随机
	math_randomseed(ngx.now() * 1000)

	return t_award_pool
end

--------------------------------------------------------------
-- 说明：周末好礼 状态
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_status = function()
	local t_params  		= ngx.ctx.t_params

	local t_user = mis_data.get_user()
	local n_code, t_status = get_weekend_gift_status(t_user)
	if n_code == t_retCode.n_OK then
		t_status.award_pool = {}
		for k, v in ipairs(get_weekend_gift_award_pool()) do
			t_status.award_pool[k] = {id = v.itemId, num = v.num}
		end
	end
	return n_code, t_status
end

--------------------------------------------------------------
-- 说明：周末好礼 开启
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_subscribe = function()
	local t_params  		= ngx.ctx.t_params

	local n_code, s_desc, t_weekendGiftData, t_status
	local t_user = mis_data.get_user()

	local n_operate = tonumber(t_params.operate)
	if n_operate == nil or (n_operate ~= 1 and n_operate ~= 0) then
		return t_retCode.n_OPER_ERR, "operate error: " .. tostring(t_params.operate)
	end

	n_code, t_weekendGiftData = t_user:get_weekend_gift_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_subscribe","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_weekendGiftData))
		return n_code, t_weekendGiftData
	end

	-- 重复开启/关闭
	if t_weekendGiftData.subscribe_status == n_operate then
		log.day_list("weekend_gift","weekend_gift_subscribe","operate repeated",t_params.uin,uu.to_str(n_operate),uu.to_str(t_weekendGiftData))
		return t_retCode.n_OPER_ERR, "operate repeated"
	end

	t_weekendGiftData.subscribe_status = n_operate

	n_code, s_desc = t_user:set_weekend_gift_data(t_weekendGiftData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift", "weekend_gift_subscribe", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	n_code, t_status = get_weekend_gift_status(t_user)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_subscribe","get_weekend_gift_status error",t_params.uin,uu.to_str(n_code),uu.to_str(t_status))
		return n_code, s_desc
	end

	local t_resp = {
		status = t_status
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：周末好礼 订阅领奖
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_subscribe_getaward = function()
	local t_params  		= ngx.ctx.t_params

	local n_code, s_desc, t_weekendGiftData, t_status
	local t_user = mis_data.get_user()
	local n_now = mis_data.weekend_gift_now()
	local n_weekday, n_week, n_hour, n_min
	local t_conf, t_award, t_award_pool, t_award_record

	-- 只能在周五、六、日抽奖
	n_weekday = tonumber(os_date("%w", n_now))
	if n_weekday ~= 5 and n_weekday ~= 6 and n_weekday ~= 0 then
		log.day_list("weekend_gift","weekend_gift_subscribe_getaward","day error",t_params.uin, n_weekday)
		return t_retCode.n_OPER_ERR, "day error"
	end

	-- 配置
	t_conf 	= mis_data.t_weekend_gift.t_conf

	-- 判断是否到达抽奖时间
	n_hour = tonumber(os_date("%H", n_now))
	n_min = tonumber(os_date("%M", n_now))
	if n_hour < t_conf.t_rotate_start.hour
	or n_hour > t_conf.t_rotate_end.hour
	or (n_hour == t_conf.t_rotate_start.hour and n_min < t_conf.t_rotate_start.min)
	or (n_hour == t_conf.t_rotate_end.hour and n_min > t_conf.t_rotate_end.min)
	then
		log.day_list("weekend_gift","weekend_gift_subscribe_getaward","not reward time",t_params.uin,uu.to_str(n_hour),uu.to_str(n_min),uu.to_str(t_conf.t_rotate_start),uu.to_str(t_conf.t_rotate_end))
		return t_retCode.n_OPER_ERR, "not reward time"
	end

	n_code, t_weekendGiftData = t_user:get_weekend_gift_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_subscribe_getaward","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_weekendGiftData))
		return n_code, t_weekendGiftData
	end

	-- 判断本周是否可领取订阅奖励
	if t_weekendGiftData.subscribe_status ~= 1 then
		log.day_list("weekend_gift","weekend_gift_subscribe_getaward","not subscribe status",t_params.uin,uu.to_str(t_weekendGiftData))
		return t_retCode.n_OPER_ERR, "not subscribe status"
	end

	if t_weekendGiftData.subscribe_reward_time
	and os_date("%Y%W", n_now) == os_date("%Y%W", t_weekendGiftData.subscribe_reward_time) then
		log.day_list("weekend_gift","weekend_gift_subscribe_getaward","already get award",t_params.uin,uu.to_str(t_weekendGiftData))
		return t_retCode.n_OPER_ERR, "already get award"
	end

	t_weekendGiftData.subscribe_reward_time = n_now

	-- 抽奖
	t_award_pool = {}
	t_award_record = t_weekendGiftData.subscribe_award_record or {}
	for _, v in pairs(mis_data.t_weekend_gift.t_conf.t_subscribe_award) do
		if v.rotate_once ~= 1 or not t_award_record[v.itemId] then
			table_insert(t_award_pool, v)
		end
	end

	-- 从奖池随机抽一个
	t_award = {}
	if #t_award_pool > 0 then
		local tmp = t_award_pool[math_random(1, #t_award_pool)]
		t_award_record[tmp.itemId] = 1
		t_weekendGiftData.subscribe_award_record = t_award_record
		table_insert(t_award, {
			id = tmp.itemId,
			num = tmp.num,
		})
	end

	n_code, s_desc = t_user:set_weekend_gift_data(t_weekendGiftData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift", "weekend_gift_subscribe", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	n_code, s_desc = mis_data.add_items(t_params.uin, t_award, mis_config.t_workType.s_WEEKEND_GIFT, 'weekend_gift_subscribe')
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_subscribe","add_items error",t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(t_award))
		return n_code, s_desc
	end

	n_code, t_status = get_weekend_gift_status(t_user)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_subscribe","get_weekend_gift_status error",t_params.uin,uu.to_str(n_code),uu.to_str(t_status))
		return n_code, s_desc
	end

	local t_resp = {
		award = t_award,
		status = t_status
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：周末好礼 抽奖
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_rotate = function()
	-- 参与状态：0未开启，1已开启，2可领奖
	-- 助力状态：0不可助力，1可助力, 2已助力
	local t_params  		= ngx.ctx.t_params

	local n_code, s_desc, t_weekendGiftData
	local n_rand, n_selectId, n_ratio_sum, n_ratio_total
	local t_ratio, t_rotate_record, t_ratio_conf
	local t_user = mis_data.get_user()
	local t_conf, t_award, t_award_pool, t_status
	local n_now = mis_data.weekend_gift_now()
	local n_weekday, n_week, n_hour, n_min

	-- 只能在周五、六、日抽奖
	n_weekday = tonumber(os_date("%w", n_now))
	if n_weekday ~= 5 and n_weekday ~= 6 and n_weekday ~= 0 then
		log.day_list("weekend_gift","weekend_gift_rotate","rotate day error",t_params.uin, n_weekday)
		return t_retCode.n_OPER_ERR, "rotate day error"
	end

	-- 配置
	t_conf 	= mis_data.t_weekend_gift.t_conf

	-- 判断是否到达抽奖时间
	n_hour = tonumber(os_date("%H", n_now))
	n_min = tonumber(os_date("%M", n_now))
	if n_hour < t_conf.t_rotate_start.hour
	or n_hour > t_conf.t_rotate_end.hour
	or (n_hour == t_conf.t_rotate_start.hour and n_min < t_conf.t_rotate_start.min)
	or (n_hour == t_conf.t_rotate_end.hour and n_min > t_conf.t_rotate_end.min)
	then
		log.day_list("weekend_gift","weekend_gift_rotate","not rotate time",t_params.uin,uu.to_str(n_hour),uu.to_str(n_min),uu.to_str(t_conf.t_rotate_start),uu.to_str(t_conf.t_rotate_end))
		return t_retCode.n_OPER_ERR, "not rotate time"
	end

	n_code, t_weekendGiftData = t_user:get_weekend_gift_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_rotate","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_weekendGiftData))
		return n_code, t_weekendGiftData
	end

	-- 判断抽奖次数截止时间（每周一0点刷新）
	if t_weekendGiftData.last_login_time
	and os_date("%Y%W", n_now) ~= os_date("%Y%W", t_weekendGiftData.last_login_time)  then
		log.day_list("weekend_gift","weekend_gift_rotate","rotate over time",t_params.uin)
		return t_retCode.n_OPER_ERR, "rotate count is zero"
	end

	-- 判断抽奖次数是否有效
	if not t_weekendGiftData.rotate_count or t_weekendGiftData.rotate_count <= 0 then
		log.day_list("weekend_gift","weekend_gift_rotate","rotate count zero",t_params.uin)
		return t_retCode.n_OPER_ERR, "rotate count is zero"
	end

	-- 判断已抽奖次数（每周最多3次）
	if t_weekendGiftData.rotate_index and t_weekendGiftData.rotate_index >= 3 then
		log.day_list("weekend_gift","weekend_gift_rotate","rotate count max",t_params.uin)
		return t_retCode.n_OPER_ERR, "rotate count max"
	end

	-- 刷新抽奖次数
	t_weekendGiftData.rotate_count = t_weekendGiftData.rotate_count - 1
	t_weekendGiftData.rotate_index = (t_weekendGiftData.rotate_index or 0) + 1

	t_ratio_conf = t_conf.t_login_award_ratio[t_weekendGiftData.rotate_index]
	if t_ratio_conf == nil then
		-- 第三个必中
		t_ratio_conf = {}
		for i = 1, 3 do
			t_ratio_conf[i] = 100
		end
	end

	-- 已中过的奖不能再中
	n_ratio_total = 0
	t_ratio = {}
	t_rotate_record = t_weekendGiftData.rotate_record or {}
	for n_id, n_ratio in ipairs(t_ratio_conf) do
		if t_rotate_record[n_id] == nil then
			t_ratio[n_id] = n_ratio
			n_ratio_total = n_ratio_total + n_ratio
		end
	end

	-- 抽奖
	n_ratio_sum = 0
	n_rand = math_random(1, n_ratio_total)
	for n_id, n_ratio in pairs(t_ratio) do
		n_ratio_sum = n_ratio_sum + n_ratio
		if n_rand <= n_ratio_sum  then n_selectId = n_id; break end
	end

	if n_selectId == nil then
		log.day_list("weekend_gift" ,"weekend_gift_rotate", "n_selectId error", t_params.uin, uu.to_str(t_weekendGiftData), uu.to_str(t_conf.t_login_award_ratio))
		return t_retCode.n_OPER_ERR, "rotate select error"
	end

	-- 记录本次抽奖
	t_rotate_record[n_selectId] = 1
	t_weekendGiftData.rotate_record = t_rotate_record

	n_code, s_desc = t_user:set_weekend_gift_data(t_weekendGiftData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift" ,"weekend_gift_rotate", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- 生成奖池
	t_award_pool = get_weekend_gift_award_pool()

	-- log.day_list("weekend_gift","weekend_gift_rotate","gift rotate",t_params.uin,uu.to_str(t_award_pool), uu.to_str(n_selectId), uu.to_str(t_weekendGiftData), uu.to_str(n_ratio_total), uu.to_str(t_ratio))

	t_award = {
		[1] = {
			id = t_award_pool[n_selectId].itemId,
			num = t_award_pool[n_selectId].num,
		}
	}

	n_code, s_desc = mis_data.add_items(t_params.uin, t_award, mis_config.t_workType.s_WEEKEND_GIFT, 'weekend_gift_rotate')
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_rotate","add_items error",t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(t_award))
		return n_code, s_desc
	end

	n_code, t_status = get_weekend_gift_status(t_user)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_rotate","get_weekend_gift_status error",t_params.uin,uu.to_str(n_code),uu.to_str(t_status))
		return n_code, s_desc
	end

	local t_resp = {
		award = t_award,
		status = t_status
	}

	-- log.day_list("weekend_gift","weekend_gift_rotate","ok",t_params.uin,uu.to_str(t_award))

	--埋点数据
	-- mis_log.remote_pure_day('weekend_gift', mis_common.table_to_json({
	-- 	key = 'weekend_gift_rotate';
	-- 	ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
	-- 	uin = t_params.uin;
	-- 	time = n_now;
	-- 	country = t_params.country or 'nil';
	-- 	apiid = t_params.apiid or 'nil';
	-- 	ver = t_params.ver or 'nil';
	-- 	lang = t_params.lang or 'nil';
	-- }))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：周末好礼 登录更新抽奖次数
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_login = function()
	local t_params  		= ngx.ctx.t_params

	local n_code, s_desc, t_weekendGiftData
	local t_user = mis_data.get_user()
	local n_now = mis_data.weekend_gift_now()
	local n_weekday

	-- 只能在周五、六、日有效
	n_weekday = tonumber(os_date("%w", n_now))
	if n_weekday ~= 5 and n_weekday ~= 6 and n_weekday ~= 0 then
		log.day_list("weekend_gift","weekend_gift_login","login day error",t_params.uin, n_weekday)
		return t_retCode.n_OPER_ERR, "login day error"
	end

	n_code, t_weekendGiftData = t_user:get_weekend_gift_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift","weekend_gift_login","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_weekendGiftData))
		return n_code, t_weekendGiftData
	end

	-- 判断当天是否已经领取过
	if t_weekendGiftData.last_login_time
	and os_date("%Y%m%d", t_weekendGiftData.last_login_time) == os_date("%Y%m%d", n_now) then
		log.day_list("weekend_gift","weekend_gift_login","already get rotate today",t_params.uin)
		return t_retCode.n_OPER_ERR, "already get rotate today"
	end

	-- 判断是否同一周登录
	if t_weekendGiftData.last_login_time
	and os_date("%Y%W", n_now) ~= os_date("%Y%W", t_weekendGiftData.last_login_time)  then
		t_weekendGiftData.rotate_index = 0
		t_weekendGiftData.rotate_count = 0
		t_weekendGiftData.rotate_record = {}
	end

	-- 判断已抽奖次数（每周最多3次）
	if t_weekendGiftData.rotate_index and t_weekendGiftData.rotate_index >= 3 then
		log.day_list("weekend_gift","weekend_gift_login","rotate count max",t_params.uin)
		return t_retCode.n_OPER_ERR, "rotate count max"
	end

	-- 刷新抽奖次数
	t_weekendGiftData.last_login_time = n_now
	t_weekendGiftData.rotate_count = (t_weekendGiftData.rotate_count or 0) + 1

	n_code, s_desc = t_user:set_weekend_gift_data(t_weekendGiftData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift" ,"weekend_gift_login", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- log.day_list("weekend_gift" ,"weekend_gift_login", "ok", t_params.uin, uu.to_str(t_weekendGiftData))

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：国宝复刻 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_relic_imitate = function()
	local t_params = ngx.ctx.t_params

	--现网屏蔽先
	-- if mis_config.n_debug ~= 1 then
	-- 	return t_retCode.n_OPER_ERR, 'relic_imitate disable2'
	-- end

	local n_now = mis_data.test_offset_now(mis_data.t_relic_imitate)
	local t_conf = mis_data.t_relic_imitate
	if t_conf.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'relic_imitate disable'
	end
	if t_conf.t_conf.n_startTime and n_now < t_conf.t_conf.n_startTime then
		return t_retCode.n_OPER_ERR, 'relic_imitate out of time'
	end
	if t_conf.t_conf.n_endTime and t_conf.t_conf.n_endTime < n_now then
		return t_retCode.n_OPER_ERR, 'relic_imitate out of time'
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：国宝复刻 状态
-- 返回：n					状态码
--		ts 					描述
this.relic_imitate_status = function()
	local t_params  		= ngx.ctx.t_params
	local n_code, t_status, t_relicImitateData, t_relicImitateMapData
	local t_sysUser = mis_data.get_user(0)
	local t_user = mis_data.get_user()
	local t_map_conf, t_map_list, t_resp

	n_code, t_relicImitateData = t_user:get_relic_imitate_data(true)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_status","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateData))
		return n_code, t_relicImitateData
	end

	t_map_conf = mis_data.t_relic_imitate.t_conf.t_vote_map
	t_map_list = {}
	for _, v in pairs(t_map_conf) do
		table_insert(t_map_list, v.map_id)
	end

	n_code, t_relicImitateMapData = t_sysUser:get_relic_imitate_map_data_batch(t_map_list)

	-- log.day_list("relic_imitate","relic_imitate_status","get map batch ret",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateMapData))

	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_status","get map data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateMapData))
		return n_code, t_relicImitateMapData
	end

	t_map_list = {}
	for _, v in pairs(t_map_conf) do
		local s_key = mis_config.t_ssdbKey.s_RELIC_IMITATE_MAP .. v.map_id
		if t_relicImitateMapData[s_key] then
			table_insert(t_map_list, {map_id = v.map_id, vote = t_relicImitateMapData[s_key].vote or 0})
		else
			table_insert(t_map_list, {map_id = v.map_id, vote = 0})
		end
	end

	t_resp = {
		-- fresh guy support one ticket
		ticket_count = t_relicImitateData.ticket_count or 1,
		vote_count = t_relicImitateData.vote_count or 0,
		map_list = t_map_list,
		award_record = t_relicImitateData.award_record or {}
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：国宝复刻 投票
-- 返回：n					状态码
--		ts 					描述
this.relic_imitate_vote = function()
	local t_params  		= ngx.ctx.t_params
	local n_mapId  			= tonumber(ngx.ctx.t_params.map_id)
	local n_code, s_desc, t_relicImitateData, t_relicImitateMapData
	local t_sysUser = mis_data.get_user(0)
	local t_user = mis_data.get_user()
	local b_exists, t_map_list, t_resp

	-- 加个锁，防止刷票
	local b_ok, e_err, b_f = t_cache:add("relic_imitate_vote" .. t_params.uin, 1, 0.2)
	if not b_ok then
		log.day_list("relic_imitate" ,"relic_imitate_vote", "vote frequently", t_params.uin, uu.to_str(e_err), uu.to_str(b_f))
		return t_retCode.n_OPER_ERR, 'vote frequently'
	end

	t_map_list = mis_data.t_relic_imitate.t_conf.t_vote_map
	b_exists = false
	for _, v in pairs(t_map_list) do
		if v.map_id == n_mapId then
			b_exists = true
			break
		end
	end
	if not b_exists then
		log.day_list("relic_imitate","relic_imitate_vote","map id not exists",t_params.uin, n_mapId)
		return t_retCode.n_OPER_ERR, "map id not exists"
	end

	n_code, t_relicImitateData = t_user:get_relic_imitate_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_vote","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateData))
		return n_code, t_relicImitateData
	end

	if t_relicImitateData.ticket_count and t_relicImitateData.ticket_count <= 0 then
		log.day_list("relic_imitate","relic_imitate_vote","ticket count is zero",t_params.uin)
		return t_retCode.n_OPER_ERR, "ticket count is zero"
	end

	n_code, t_relicImitateMapData = t_sysUser:get_relic_imitate_map_data(n_mapId)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_vote","get map data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateMapData))
		return n_code, t_relicImitateMapData
	end

	-- log.day_list("relic_imitate" ,"relic_imitate_vote", "before vote", t_params.uin, uu.to_str(n_mapId), uu.to_str(t_relicImitateMapData))

	t_relicImitateMapData.vote = (t_relicImitateMapData.vote or 0) + 1
	t_relicImitateData.ticket_count = (t_relicImitateData.ticket_count or 1) - 1
	t_relicImitateData.vote_count = (t_relicImitateData.vote_count or 0) + 1

	n_code, s_desc = t_sysUser:set_relic_imitate_map_data(n_mapId, t_relicImitateMapData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate" ,"relic_imitate_vote", "save map error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	n_code, s_desc = t_user:set_relic_imitate_data(t_relicImitateData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate" ,"relic_imitate_vote", "save user error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- log.day_list("relic_imitate" ,"relic_imitate_vote", "ok", t_params.uin, uu.to_str(n_mapId), uu.to_str(t_relicImitateMapData), uu.to_str(t_relicImitateData))

	--埋点数据
	mis_log.remote_pure_day('relic_imitate_vote', mis_common.table_to_json({
		key = 'reprint2021_vote';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = mis_data.test_offset_now(mis_data.t_relic_imitate);
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		mapid = n_mapId or 'nil';
	}))

	t_resp = {
		ticket_count = t_relicImitateData.ticket_count or 0,
		vote_count = t_relicImitateData.vote_count or 0,
		map_list = {{map_id = n_mapId, vote = t_relicImitateMapData.vote}},
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：国宝复刻 投票领奖
-- 返回：n					状态码
--		ts 					描述
this.relic_imitate_vote_getaward = function()
	local t_params  		= ngx.ctx.t_params
	local n_award_index		= tonumber(t_params.award_index)
	local n_code, s_desc, t_relicImitateData
	local t_user = mis_data.get_user()
	local t_award_conf, t_award_list, t_resp

	n_code, t_relicImitateData = t_user:get_relic_imitate_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_vote_getaward","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateData))
		return n_code, t_relicImitateData
	end

	-- 已经领取
	if t_relicImitateData.award_record and t_relicImitateData.award_record[n_award_index] ~= nil then
		log.day_list("relic_imitate","relic_imitate_vote_getaward","award been fetched",t_params.uin,t_params.award_index)
		return t_retCode.n_OPER_ERR, "award been fetched"
	end

	t_award_conf = mis_data.t_relic_imitate.t_conf.t_vote_award

	if not t_award_conf[n_award_index] then
		log.day_list("relic_imitate","relic_imitate_vote_getaward","award index error",t_params.uin,t_params.award_index)
		return t_retCode.n_OPER_ERR, "award index error"
	end

	if not t_relicImitateData.vote_count
	or t_relicImitateData.vote_count < t_award_conf[n_award_index].vote_count then
		log.day_list("relic_imitate","relic_imitate_vote_getaward","vote count error",t_params.uin, uu.to_str(t_relicImitateData.vote_count), t_params.award_index)
		return t_retCode.n_OPER_ERR, "vote count error"
	end

	if t_relicImitateData.award_record == nil then
		t_relicImitateData.award_record = {}
	end
	t_relicImitateData.award_record[n_award_index] = 1

	-- 发放道具
	t_award_list = {}
	for _, v in ipairs(t_award_conf[n_award_index].bonus) do
		table_insert(t_award_list, {id = v.itemId, num = v.num})
	end

	n_code, s_desc = t_user:set_relic_imitate_data(t_relicImitateData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate" ,"relic_imitate_vote_getaward", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	n_code, s_desc = mis_data.add_items(t_params.uin, t_award_list, mis_config.t_workType.s_RELIC_IMITATE, 'relic_imitate_vote_getaward')
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_vote_getaward","add_items error",t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(t_award_list))
		return n_code, s_desc
	end

	--埋点数据
	mis_log.remote_pure_day('relic_imitate_award', mis_common.table_to_json({
		key = 'reprint2021_receive';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = mis_data.test_offset_now(mis_data.t_relic_imitate);
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		bonus = n_award_index or 'nil';
	}))

	t_resp = {
		award_list = t_award_list,
		award_record = t_relicImitateData.award_record
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：国宝复刻 触发任务
-- 返回：n					状态码
--		ts 					描述
this.relic_imitate_task_event = function(n_event, b_readOnly, b_force)
	local t_params  		= ngx.ctx.t_params
	local n_event			= tonumber(n_event or t_params.event)
	local n_code, s_desc, t_relicImitateData
	local t_user = mis_data.get_user()
	local n_now = mis_data.test_offset_now(mis_data.t_relic_imitate)
	local n_refreshTime, t_task, t_resp

	n_code, t_relicImitateData = t_user:get_relic_imitate_data(b_readOnly, b_force)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_task_event","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateData))
		return n_code, t_relicImitateData
	end

	-- 每日刷新
	n_refreshTime = t_relicImitateData.refreshTime
	if n_refreshTime == nil
	or os_date("%Y%m%d", n_refreshTime) ~= os_date("%Y%m%d", n_now) then
		t_relicImitateData.task = {}
		t_relicImitateData.refreshTime = n_now
	end

	local t_task_conf = mis_data.t_relic_imitate.t_conf.t_mission

	t_task = t_relicImitateData.task or {}

	for k, v in ipairs(t_task_conf) do
		if v.event == n_event then
			if not t_task[k] then
				t_task[k] = {status = 0, progress = 1}
			elseif t_task[k].status == 0 then
				-- 更新进度
				t_task[k].progress = t_task[k].progress + 1
			end
			-- 任务完成
			if t_task[k].status == 0 and t_task[k].progress >= v.target then
				t_task[k].status = 1
			end
		end
	end

	t_relicImitateData.task = t_task

	if not b_readOnly then
		n_code, s_desc = t_user:set_relic_imitate_data(t_relicImitateData)
		if n_code ~= t_retCode.n_OK then
			log.day_list("relic_imitate" ,"relic_imitate_task_event", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
			return n_code, s_desc
		end
	end

	-- 任务列表
	local t_task_list = {}
	for k, v in ipairs(t_task_conf) do
		if not t_task[k] then
			table_insert(t_task_list, {
				task_index = k,
				task_progress = 0,
				task_status = 0
			})
		else
			table_insert(t_task_list, {
				task_index = k,
				task_progress = t_task[k].progress,
				task_status = t_task[k].status
			})
		end
	end

	t_resp = {
		task_list = t_task_list
	}

	-- log.day_list("relic_imitate","relic_imitate_task_event","ok",t_params.uin, uu.to_str(n_event), uu.to_str(b_readOnly), uu.to_str(t_relicImitateData), uu.to_str(t_resp))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：国宝复刻 领取任务奖励
-- 返回：n					状态码
--		ts 					描述
this.relic_imitate_get_vote_ticket = function()
	local t_params  		= ngx.ctx.t_params
	local n_task_index		= tonumber(t_params.task_id)
	local n_code, s_desc, t_relicImitateData
	local t_user = mis_data.get_user()
	local n_now = mis_data.test_offset_now(mis_data.t_relic_imitate)
	local n_refreshTime, t_task, t_resp

	n_code, t_relicImitateData = t_user:get_relic_imitate_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_get_vote_ticket","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateData))
		return n_code, t_relicImitateData
	end

	-- 每日刷新
	n_refreshTime = t_relicImitateData.refreshTime
	if n_refreshTime == nil
	or os_date("%Y%m%d", n_refreshTime) ~= os_date("%Y%m%d", n_now) then
		this.relic_imitate_task_event(18, true)
	end

	local t_task_conf = mis_data.t_relic_imitate.t_conf.t_mission

	t_task = t_relicImitateData.task
	if not t_task
	or t_task[n_task_index] == nil
	or t_task[n_task_index].status ~= 1
	then
		log.day_list("relic_imitate","relic_imitate_get_vote_ticket","task status error",t_params.uin,t_params.task_id)
		return t_retCode.n_OPER_ERR, "task status error"
	end

	-- 记录为已领奖
	t_task[n_task_index].status = 2
	t_relicImitateData.ticket_count = (t_relicImitateData.ticket_count or 0) + t_task_conf[n_task_index].vote_ticket

	n_code, s_desc = t_user:set_relic_imitate_data(t_relicImitateData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate" ,"relic_imitate_get_vote_ticket", "save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- 任务列表
	local t_task_list = {}
	for k, v in ipairs(t_task_conf) do
		if not t_task[k] then
			table_insert(t_task_list, {
				task_index = k,
				task_progress = 0,
				task_status = 0
			})
		else
			table_insert(t_task_list, {
				task_index = k,
				task_progress = t_task[k].progress,
				task_status = t_task[k].status
			})
		end
	end

	t_resp = {
		task_list = t_task_list,
		ticket_count = t_relicImitateData.ticket_count
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：国宝复刻 任务列表
-- 返回：n					状态码
--		ts 					描述
this.relic_imitate_task_list = function()
	local t_params  		= ngx.ctx.t_params
	local n_code, s_desc, t_relicImitateData
	local t_user = mis_data.get_user()
	local n_now = mis_data.test_offset_now(mis_data.t_relic_imitate)
	local n_refreshTime, t_task, t_resp

	n_code, t_relicImitateData = t_user:get_relic_imitate_data(true)
	if n_code ~= t_retCode.n_OK then
		log.day_list("relic_imitate","relic_imitate_task_list","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_relicImitateData))
		return n_code, t_relicImitateData
	end

	local t_task_conf = mis_data.t_relic_imitate.t_conf.t_mission

	-- 每日刷新
	n_refreshTime = t_relicImitateData.refreshTime
	if n_refreshTime == nil
	or os_date("%Y%m%d", n_refreshTime) ~= os_date("%Y%m%d", n_now) then
		this.relic_imitate_task_event(18, false, true)
	end

	t_task = t_relicImitateData.task or {}

	-- 任务列表
	local t_task_list = {}
	for k, v in ipairs(t_task_conf) do
		if not t_task[k] then
			table_insert(t_task_list, {
				task_index = k,
				task_progress = 0,
				task_status = 0
			})
		else
			table_insert(t_task_list, {
				task_index = k,
				task_progress = t_task[k].progress,
				task_status = t_task[k].status
			})
		end
	end

	t_resp = {
		task_list = t_task_list,
	}

	return t_retCode.n_OK, t_resp
end


--------------------------------------------------------------
-- 说明：音乐嘉年华 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_concert = function()
	local t_params  		= ngx.ctx.t_params
	local t_concert 		= mis_data.t_concert
	local s_type			= t_params.festival_type
	local n_nowtime 		= mis_data.get_server_time()

	if t_concert.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'concert disable'
	end

	-- 活动有效期间
	if n_nowtime < t_concert.t_conf.n_startTime or n_nowtime > t_concert.t_conf.n_endTime then
		return t_retCode.n_OPER_ERR, 'Activity is out of validity!'
	end

	-- 任务有效时间
	if s_type then
		local n_taskID 	   = mis_config.t_concertMap[s_type]
		local t_taskList   = t_concert.t_conf.t_taskList or {}
		local t_task

		if n_taskID and t_taskList[n_taskID] then t_task = t_taskList[n_taskID] end
		if t_task and t_task.n_startTime and t_task.n_endTime then
			if n_nowtime < t_task.n_startTime or n_nowtime > t_task.n_endTime then
				return t_retCode.n_OPER_ERR, 'The task is not within the validity period!'
			end
		end
	end

	-- 渠道控制
	if mis_uu.tableNotEmpty(t_concert.t_conf.apiids) then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)

		for _, v in pairs(t_concert.t_conf.t_apiids) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if not b_valid_apiid then
			return t_retCode.n_OPER_ERR, 'apiid is invalid'
		end
	end

	-- 版本号控制
	local n_l = mis_common.version_to_number(t_params.ver or 0)
	local n_r = t_concert.t_conf.n_version_min
	if n_l < n_r then
		return t_retCode.n_OPER_ERR, 'version too low'
	end

	return t_retCode.n_OK
end

local concert_event_core = function(t_userData, n_taskID, n_event, n_value)
	local n_nowTime 		= mis_data.get_server_time()
	local t_concertConf 	= mis_data.t_concert.t_conf
	local t_taskList 		= t_concertConf.t_taskList or {}
	local t_temp, t_mission = {}, {}

	if not(t_userData and mis_uu.tableNotEmpty(t_userData)) then
		return t_retCode.n_PARAM_ERR, "param error"
	end

	if not(n_taskID and n_value) then
		return t_retCode.n_PARAM_ERR, "param error"
	end

	if not (n_taskID and t_taskList[n_taskID] and t_taskList[n_taskID].t_mission and t_userData.tasks[n_taskID]) then
		mis_log.day("concert_error", "concert_event_core type error|" .. n_taskID .. '|' .. n_event)
		return t_retCode.n_PARAM_ERR, "concert type error"
	end

	-- 获取子任务配置
	t_temp = t_taskList[n_taskID].t_mission
	for k, v in pairs(t_temp) do
		if k == n_event then
			t_mission = v
			break
		end
	end

	if not (t_mission and mis_uu.tableNotEmpty(t_mission)) then
		return t_retCode.n_PARAM_ERR, "mission not exist"
	end

	-- 更新任务进度、状态
	for k, v in pairs(t_mission) do
		local t_task = t_userData.tasks[n_taskID][v.n_subTaskId]
		if not t_task then
			t_task = {status = 0, progress = 0, refreshTime = 0 }
		end

		-- 更新进度
		if t_task.status == 0 then
			-- 获得指定道具类型的任务
			if n_event == 30 then
				if v.n_gain_item == n_value then
					t_task.progress	= t_task.progress + 1
					t_task.refreshTime 	= n_nowTime
				end
			else
				t_task.progress = t_task.progress + n_value
				t_task.refreshTime 	= n_nowTime
			end
		end
		-- 任务完成
		if t_task.status == 0 and v.n_target and t_task.progress >= v.n_target then
			t_task.status 		= 1
			t_task.progress		= v.n_target
			t_task.refreshTime 	= n_nowTime
		end
		t_userData.tasks[n_taskID][v.n_subTaskId] = t_task
	end

	return t_retCode.n_OK, t_userData
end

local concert_getaward_core = function(t_userData, n_taskID, n_subTaskId, n_mode, t_mission)
	local t_params 			= ngx.ctx.t_params
	local n_nowTime 		= mis_data.get_server_time()
	local t_concertMap		= mis_config.t_concertMap
	local b_valid 			= false
	local t_task 			= {}
	local n_total 			= 0

	if not(n_taskID and n_mode and t_userData and mis_uu.tableNotEmpty(t_userData) and
			t_userData.tasks and mis_uu.tableNotEmpty(t_userData.tasks) and
			t_mission and mis_uu.tableNotEmpty(t_mission) and
			t_mission.t_bonus and mis_uu.tableNotEmpty(t_mission.t_bonus)) then
		mis_log.day("concert_error", "concert_getaward_core param error|" .. t_params.uin .. uu.to_str(t_params.festival_type))
		return 0, t_userData
	end

	-- 更新领奖状态
	for k, v in pairs(t_mission.t_bonus) do
		n_total = n_total + (v.n_num or 0)
	end

	t_task = t_userData.tasks[n_taskID]
	if not t_task then
		return 0, t_userData
	end

	for k, v in pairs(t_task) do
		if k == n_subTaskId then
			if v.status == 1 then
				v.status 		= 2
				v.mode			= n_mode				-- 0 手动领奖；1自动领奖
				--v.refreshTime	= n_nowTime
				v.rewardTime 	= n_nowTime
				b_valid			= true
			end
			break
		end
	end

	if b_valid == false then
		mis_log.day("concert_error", "concert_getaward_core Invalid reward|" .. t_params.uin .. uu.to_str(t_params.festival_type))
		return 0, t_userData
	end

	t_userData.tasks[n_taskID] 	= t_task
	t_userData.note_num 		= t_userData.note_num + n_total

	--埋点数据
	mis_log.remote_pure_day('concert_record', mis_common.table_to_json({
		key = 'concert_getaward';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = n_nowTime;
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		type = t_concertMap[n_taskID] or 'nil';
		task = n_subTaskId;
		mode = n_mode;
		note_num = n_total;
	}))

	return n_total, t_userData
end

--------------------------------------------------------------
-- 说明：音乐嘉年华 任务状态
-- 返回：n					状态码
--		ts 					描述
this.concert_status = function()
	local t_params 			= ngx.ctx.t_params
	local t_concertConf 	= mis_data.t_concert.t_conf
	local t_taskList 		= t_concertConf.t_taskList or {}
	local t_concertMap		= mis_config.t_concertMap
	local t_userTasks		= {}
	local n_nowtime 		= mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData, n_taskID

	-- 获取音乐嘉年华数据
	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_concert_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user concert data error'
	end
	if mis_common.tableIsEmpty(t_userData) then
		t_userData.note_num = 0
		t_userData.tasks	= {}
	end

	-- 通过配置表刷新玩家任务
	for k, v in pairs(t_taskList) do
		if v and v.n_startTime and v.n_endTime and n_nowtime >= v.n_startTime and n_nowtime <= v.n_endTime then
			t_userData.tasks[k] = t_userData.tasks[k] or {}

			for k2, v2 in pairs(v.t_mission) do

				for k3, v3 in pairs(v2) do
					local n_taskId		= v3.n_subTaskId
					local t_task 		= t_userData.tasks[k][n_taskId]
					local b_update  	= false
					local n_status		= 0
					local n_refreshTime = 0
					local n_progress	= 0

					if t_task then
						-- 自动领取奖励
						if v.b_auto and t_task.status == 1 and v3.t_bonus and mis_uu.tableNotEmpty(v3.t_bonus) and
								mis_common.is_another_day(t_task.refreshTime, n_nowtime) then

							concert_getaward_core(t_userData, k, n_taskId, 1, v3)

							t_task = t_userData.tasks[k][n_taskId]
						end
						-- 刷新任务
						if v3.b_daily and mis_common.is_another_day(t_task.refreshTime, n_nowtime) then
							b_update = true
						end
						if v3.b_weekly and mis_common.is_another_week(t_task.refreshTime, n_nowtime) then
							b_update = true
						end
						if b_update == true and t_concertMap[k] and t_concertMap[k] == 'music_xmy_appoint' then
							if t_task.status ~= 0 then n_status = 1  end
							n_progress		= t_task.progress
							n_refreshTime 	= n_nowtime
						end
					end

					-- 更新任务
					if not t_task or b_update == true then
						t_task = { progress = n_progress, status = n_status, refreshTime = n_refreshTime, rewardTime = 0, mode = 0 }
					end
					t_userData.tasks[k][n_taskId] =  t_task
				end
			end
		end
	end

	-- 清除已下线活动数据
	for k, v in pairs(t_userData.tasks) do
		if not t_taskList[k] then
			v = nil
			t_userData.tasks[k] = nil
		end
	end
	-- 触发音乐节登录游戏
	n_taskID = mis_config.t_concertMap["music_miniw"]
	n_code, s_desc = concert_event_core(t_userData, n_taskID, 18, 1)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("concert_error","concert_event login error|" .. t_params.uin .. '|' .. uu.to_str(n_code))
	end

	n_code, s_desc   = t_user:set_concert_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 客户端界面显示
	local t_resp = { note_num = t_userData.note_num, tasks = {} }
	for k, v in pairs(t_userData.tasks) do
		local s_type = mis_config.t_concertMap[k]
		if s_type then
			t_resp.tasks[s_type] = {}
			for k2, v2 in pairs(v) do
				t_resp.tasks[s_type][k2] = { progress = v2.progress, status = v2.status }
			end
		end
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：音乐嘉年华 触发任务
-- 参数：event				任务
--		value				增量
--      festival_type		活动类型
-- 返回：n					状态码
--		ts 					描述
this.concert_event = function()
	local t_params  		= ngx.ctx.t_params
	local n_event			= t_params.event
	local n_value			= t_params.count
	local s_type			= t_params.festival_type
	local n_taskID 			= mis_config.t_concertMap[s_type]
	local n_nowTime         = mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData

	t_user = mis_data.get_user()
	n_code, t_userData 	= t_user:get_concert_data()
	if n_code ~= t_retCode.n_OK or not t_userData.tasks or not t_userData.tasks[n_taskID] then
		mis_log.day("concert_error","concert_event get user data error|" .. t_params.uin .. '|' .. n_taskID)
		return n_code, t_userData
	end

	-- 更新任务进度
	n_code, s_desc = concert_event_core(t_userData, n_taskID, n_event, n_value)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("concert_error","concert_event core error|" .. t_params.uin .. '|' .. uu.to_str(n_code))
		return n_code, 'concert event core error'
	end

	n_code, s_desc = t_user:set_concert_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("concert_error","concert_event save error|" .. t_params.uin .. '|' .. uu.to_str(n_code) .. uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- 客户端界面显示
	local t_resp = { note_num = t_userData.note_num, tasks = {} }
	for k, v in pairs(t_userData.tasks) do
		if mis_config.t_concertMap[k] == s_type then
			t_resp.tasks[s_type] = {}
			for k2, v2 in pairs(v) do
				t_resp.tasks[s_type][k2] = { progress = v2.progress, status = v2.status }
			end
			break
		end
	end

	--埋点数据
	mis_log.remote_pure_day('concert_record', mis_common.table_to_json({
		key = 'concert_event';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = n_nowTime;
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		type = s_type;
		task = n_event;
		count = n_value;
	}))

	return t_retCode.n_OK, t_resp
end


--------------------------------------------------------------
-- 说明：音乐嘉年华 任务领奖
-- 返回：n					状态码
--		ts 					描述
this.concert_task_getaward = function()
	local t_params 			= ngx.ctx.t_params
	local t_concertConf 	= mis_data.t_concert.t_conf
	local t_taskList 		= t_concertConf.t_taskList or {}
	local t_mission, t_task, t_temp	= {}, {}, {}
	local n_code, s_desc, t_user, t_userData

	local n_subTaskId		= t_params.task_id
	local s_type			= t_params.festival_type
	local n_taskID 			= mis_config.t_concertMap[s_type]

	if not (n_taskID and t_taskList[n_taskID] and t_taskList[n_taskID].t_mission) then
		mis_log.day("concert_error", "concert_task_getaward type error|" .. t_params.uin .. uu.to_str(t_params.festival_type))
		return t_retCode.n_PARAM_ERR, "concert type error"
	end

	-- 获取子任务配置
	t_temp = t_taskList[n_taskID].t_mission
	for k, v in pairs(t_temp) do
		for k2, v2 in pairs(v) do
			if v2.n_subTaskId and n_subTaskId == v2.n_subTaskId then
				t_mission = v2
				break
			end
		end
	end

	if not (t_mission and mis_uu.tableNotEmpty(t_mission)) then
		mis_log.day("concert_error", "concert_task_getaward mission not exist|" .. t_params.uin .. uu.to_str(t_params.festival_type))
		return t_retCode.n_PARAM_ERR, "mission not exist"
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_concert_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user concert data error'
	end

	local n_num, _ = concert_getaward_core(t_userData, n_taskID, n_subTaskId, 0, t_mission)
	n_code, s_desc = t_user:set_concert_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 客户端界面显示
	local t_resp = { note_num = t_userData.note_num, award_num = n_num, tasks = {} }
	for k, v in pairs(t_userData.tasks) do
		if mis_config.t_concertMap[k] == s_type then
			t_resp.tasks[s_type] = {}
			for k2, v2 in pairs(v) do
				t_resp.tasks[s_type][k2] = { progress = v2.progress, status = v2.status }
			end
			break
		end
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：音乐嘉年华 音符商店兑换
-- 返回：n					状态码
--		ts 					描述
this.concert_store_exchange = function()
	local t_params 	= ngx.ctx.t_params
	local n_itemId 	= t_params.item_id
	local n_itemNum = t_params.item_num
	local n_noteNum, n_price, n_total = 0, 0, 0

	local n_code, s_desc, s_items, ts_desc, t_user, t_userData
	local t_concertConf 	= mis_data.t_concert.t_conf
	local t_store 			= t_concertConf.t_noteStore
	local t_goods			= {}
	local n_nowTime			= mis_data.get_server_time()

	if n_nowTime < t_store.n_startTime or n_nowTime > t_store.n_endTime then
		mis_log.day("concert_error", "invalid time|" .. t_params.uin .. '|' .. t_store.n_startTime .. '|' .. t_store.n_endTime)
		return t_retCode.n_OPER_ERR, 'invalid time'
	end

	if n_itemId <= 0 and n_itemNum <= 0 then
		mis_log.day("concert_error", "param error|" .. t_params.uin .. '|' .. n_itemId .. '|' .. n_itemNum)
		return t_retCode.n_PARAM_ERR, 'param error'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_concert_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user concert data error'
	end

	if not (t_store.t_goods and t_store.t_goods[n_itemId] and t_store.t_goods[n_itemId].price and
			t_store.t_goods[n_itemId].t_items and mis_uu.tableNotEmpty(t_store.t_goods[n_itemId].t_items)) then
		return t_retCode.n_PARAM_ERR, 'goods is not exist'
	end

	t_goods   = t_store.t_goods[n_itemId]
	n_price   = t_goods.price
	n_total   = n_itemNum * n_price
	n_noteNum = tonumber(t_userData.note_num)
	if n_total > n_noteNum or n_total <= 0 then
		mis_log.day("concert_error", "note num is not enough|" .. t_params.uin .. '|' .. n_total .. '|' .. n_noteNum)
		return t_retCode.n_PARAM_ERR, 'note num is not enough'
	end

	-- 账号服校验是否已拥有
	if t_goods.limit and t_goods.limit == 1 then
		local t_contentId = {}
		local b_exist 	  = false
		for k, v in pairs(t_goods.t_items) do
			if v.id then table.insert(t_contentId, v.id) end
		end
		n_code, ts_desc = mis_bridge.check_item_exist(t_params.uin, mis_common.table_to_json(t_contentId))
		if n_code ~= t_retCode.n_OK then
			mis_log.day("concert_error", "check_item_exist|" .. t_params.uin .. '|' .. mis_common.table_to_json(t_contentId))
			return n_code, ts_desc
		end
		for _, t_ in pairs(ts_desc) do
			if t_.canget == false then
				b_exist = true
				break
			end
		end
		if b_exist then
			mis_log.day("concert_error", "already owned|" .. t_params.uin .. '|' .. mis_common.table_to_json(t_contentId))
			return t_retCode.n_OPER_ERR, 'already owned'
		end
	end

	-- 发放道具
	n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_goods.t_items, mis_config.t_workType.s_CONCERT, 'concert_exchange')
	if n_code ~= t_retCode.n_OK then
		mis_log.day('concert_error', 'concert exchange goods|' .. t_params.uin .. '|' .. s_items)
		return n_code, s_desc
	end

	t_userData.note_num = n_noteNum - n_total
	n_code, s_desc = t_user:set_concert_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	--埋点数据
	mis_log.remote_pure_day('concert_exchange', mis_common.table_to_json({
		key = 'concert_store_exchange';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = n_nowTime;
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		bonus = t_goods.t_items or 'nil';
	}))

	return t_retCode.n_OK, { note_num = t_userData.note_num, t_goods = t_goods.t_items }
end

--------------------------------------------------------------
-- 说明：音乐嘉年华 请求音乐密码
-- 返回：n					状态码
--		ts 					描述
this.concert_request_code = function()
	local t_params 	= ngx.ctx.t_params
	local n_uin 	= t_params.uin
	local b_ok, n_code, s_desc, s_code, t_codeData
	local t_user, t_userData
	local t_concertConf 	= mis_data.t_concert.t_conf
	local t_sysUser 		= mis_data.get_user(0)

	-- 加个锁，防止刷票
	b_ok, s_desc = t_cache:add("concert_request_code" .. n_uin, 1, 0.2)
	if not b_ok then
		log.day_list("concert" ,"concert_request_code", "request frequently", n_uin, uu.to_str(s_desc))
		return t_retCode.n_OPER_ERR, 'request frequently'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_concert_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert" ,"concert_request_code", "get user concert data error", n_uin, n_code, uu.to_str(s_desc))
		return n_code, 'get user concert data error'
	end

	-- 一天只能申请一个码
	if t_userData.concert_code 
	and os_date("%Y%m%d", t_userData.concert_code.ctime) == os_date("%Y%m%d") then
		return t_retCode.n_OK, { code = t_userData.concert_code.code }
	end

	s_code, s_desc = mis_calcu.new_concert_code(t_concertConf.t_codePrefix)
	if s_code == nil then
		log.day_list("concert","concert_request_code","new_concert_code error", n_uin, uu.to_str(s_desc))
		return t_retCode.n_SYS_ERR, "new concert code error"
	end

	log.day_list("concert" ,"concert_request_code", "new code", n_uin, uu.to_str(s_code))

	t_codeData = {ctime = uu.now(), uin = n_uin, exchange = 0, exchange_users = {}}
	n_code, s_desc = t_sysUser:set_concert_code_data(s_code, t_codeData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_request_code", "save sys code error", n_uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end
	
	t_userData.concert_code = {ctime = uu.now(), code = s_code}
	
	n_code, s_desc = t_user:set_concert_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_request_code", "save user code error", n_uin, uu.to_str(n_code), uu.to_str(s_desc), uu.to_str(t_userData.concert_code))
		return n_code, s_desc
	end

	return t_retCode.n_OK, { code = s_code }
end

--------------------------------------------------------------
-- 说明：音乐嘉年华 音乐密码兑换
-- 返回：n					状态码
--		ts 					描述
this.concert_code_exchange = function()
	local t_params 	= ngx.ctx.t_params
	local n_uin 	= t_params.uin
	local s_code 	= t_params.code
	local n_code, s_desc, t_user, t_userData
	local t_codeData, t_codeUser, t_codeUserData
	local t_concertConf 	= mis_data.t_concert.t_conf
	local n_taskID 			= mis_config.t_concertMap["music_miniw"]
	local t_sysUser 		= mis_data.get_user(0)

	-- 判断参数是否有效
	if not s_code or string_match(s_code, "^%s*$") ~= nil then
		log.day_list("concert", "concert_code_exchange", "s_code empty", n_uin, uu.to_str(s_code))
		return t_retCode.n_PARAM_ERR, 'code empty'
	end

	n_code, t_codeData = t_sysUser:get_concert_code_data(s_code, true)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "get_concert_code_data error", n_uin, uu.to_str(n_code), uu.to_str(t_codeData))
		return n_code, t_codeData
	end

	-- 密码不存在
	if t_codeData.uin == nil then
		log.day_list("concert", "concert_code_exchange", "code not exists", n_uin, uu.to_str(t_codeData))
		return t_retCode.n_CONCERT_CODE_INVALID, "code not exists"
	end

	if t_codeData.uin == n_uin then
		log.day_list("concert", "concert_code_exchange", "can't exchange self", n_uin, uu.to_str(t_codeData))
		return t_retCode.n_CONCERT_CODE_SELF_LIMIT, "can't exchange self"
	end

	-- 只能兑换2次
	if t_codeData.exchange >= 2 then
		log.day_list("concert", "concert_code_exchange", "exchange excess", n_uin, uu.to_str(t_codeData))
		return t_retCode.n_CONCERT_CODE_EXCESS, "exchange excess"
	end
	
	-- 一个用户同一个码只能兑换一次
	if t_codeData.exchange_users and t_codeData.exchange_users[n_uin] then
		log.day_list("concert", "concert_code_exchange", "exchange repeated", n_uin, uu.to_str(t_codeData))
		return t_retCode.n_CONCERT_CODE_REPEATED, "exchange repeated"
	end

	-- 已过期
	if os_date("%Y%m%d", t_codeData.ctime) ~= os_date("%Y%m%d") then
		log.day_list("concert", "concert_code_exchange", "code expire", n_uin, uu.to_str(n_code), uu.to_str(t_codeData))
		return t_retCode.n_CONCERT_CODE_EXPIRE, "code expire"
	end

	t_codeData.exchange = t_codeData.exchange + 1
	t_codeData.exchange_users = t_codeData.exchange_users or {}
	t_codeData.exchange_users[n_uin] = 1

	n_code, s_desc = t_sysUser:set_concert_code_data(s_code, t_codeData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "save error", n_uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- 发奖励
	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_concert_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "get_concert_data", n_uin, uu.to_str(n_code), uu.to_str(t_userData))
		return n_code, t_userData
	end

	-- 更新任务
	n_code, s_desc = concert_event_core(t_userData, n_taskID, 28, 1)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "update mission fail", n_uin, uu.to_str(n_code), uu.to_str(s_desc))
	end

	n_code, s_desc = t_user:set_concert_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "set_concert_data fail", n_uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- 分享者发奖励
	t_codeUser = mis_data.get_user(t_codeData.uin)
	n_code, t_codeUserData = t_codeUser:get_concert_data()
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "get_concert_data", t_codeData.uin, uu.to_str(n_code), uu.to_str(t_codeUserData))
		return n_code, t_codeUserData
	end

	-- 更新任务
	n_code, s_desc = concert_event_core(t_codeUserData, n_taskID, 29, 1)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "update mission fail", t_codeData.uin, uu.to_str(n_code), uu.to_str(s_desc))
	end

	n_code, s_desc = t_codeUser:set_concert_data(t_codeUserData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("concert", "concert_code_exchange", "set_concert_data fail", t_codeData.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end
	
	log.day_list("concert", "concert_code_exchange", "ok", n_uin, uu.to_str(t_codeData), t_codeData.uin, uu.to_str(t_codeUserData))

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：每日签到 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_daily_sign = function()
	local t_params  		= ngx.ctx.t_params
	local t_daily_sign 		= mis_data.t_daily_sign
	local n_nowtime 		= mis_data.offset_now_v2(t_daily_sign)

	if t_daily_sign.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'daily_sign disable'
	end

	-- 活动有效期间
	if n_nowtime < t_daily_sign.t_conf.n_startTime or n_nowtime > t_daily_sign.t_conf.n_endTime then
		return t_retCode.n_OPER_ERR, 'not within the validity period'
	end

	-- 渠道控制
	if mis_uu.tableNotEmpty(t_daily_sign.t_conf.apiids) then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)

		for _, v in pairs(t_daily_sign.t_conf.t_apiids) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if not b_valid_apiid then
			return t_retCode.n_OPER_ERR, 'apiid is invalid'
		end
	end

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：每日签到状态
-- 返回：n					状态码
--		ts 					描述
this.daily_sign_status = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local t_conf			= mis_data.t_daily_sign.t_conf
	local n_now 			= mis_data.offset_now_v2(t_conf)
	local n_code, s_desc, t_user, t_userData, t_activity
	local n_regDays, n_refreshTime, b_lowActive, t_resp
	local n_bucketId, n_res, n_lastLoginInterval, n_notifyFlag

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_daily_sign_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user daily_sign data error'
	end

	n_refreshTime = t_userData.refresh_time
	-- 更新刷新时间
	t_userData.refresh_time = n_now

	-- 每周刷新
	if n_refreshTime == nil
	or os_date("%Y%W", n_refreshTime) ~= os_date("%Y%W", n_now)
	then
		-- 数据已过期，从数据库重新获取
		n_code, t_activity = t_user:get_activity_data()
		if n_code ~= t_retCode.n_OK then
			log.day_list("daily_sign", "daily_sign_status", "get_activity_data fail", n_uin, uu.to_str(n_code), uu.to_str(t_activity))
			return n_code, "mysql error"
		end
		
		log.day_list("daily_sign", "daily_sign_status", "get_activity_data ret", n_uin, uu.to_str(t_activity))

		if #t_activity == 0 then
			t_activity = {
				reg_date = 0, 
				last_30d_logins = 0, 
				is_adult = 1, 
				is_identified = 1,
				last_login_date = 0,
			}
		else
			t_activity = t_activity[1]
		end
		
		n_regDays = (n_now - t_activity.reg_date) / 86400
		n_lastLoginInterval = (n_now - t_activity.last_login_date) / 86400
		b_lowActive = (n_regDays >= 30 and t_activity.last_30d_logins <= 3 and n_lastLoginInterval <= 6)

		t_activity.notify_flag = b_lowActive and 1 or 0
		t_activity.low_active = b_lowActive and 1 or 0
		t_userData.activity = t_activity
		t_userData.week_sign = {
			[1] = 0,
			[2] = 0,
			[3] = 0,
			[4] = 0,
			[5] = 0,
			[6] = 0,
			[7] = 0,
		}
		if t_activity.is_identified == 1 and t_activity.is_adult == 1 then
			t_userData.sign_card_count = t_conf.t_adult_sign.sign_card_count
			t_userData.sign_card_count_max = t_conf.t_adult_sign.sign_card_count
		else
			t_userData.sign_card_count = t_conf.t_under_age_sign.sign_card_count
			t_userData.sign_card_count_max = t_conf.t_under_age_sign.sign_card_count
		end
		
		log.day_list("daily_sign", "daily_sign_status", "daily_sign refresh", n_uin, uu.to_str(n_regDays), uu.to_str(n_lastLoginInterval), uu.to_str(t_userData))
	else
		t_activity = t_userData.activity	
	end

	-- 拍脸标识
	n_notifyFlag = 0

	-- 拍脸：低活、一天最多一次、拍一整周
	if t_conf.n_notice_control == 1 and (n_refreshTime == nil
	or os_date("%Y%m%d", n_refreshTime) ~= os_date("%Y%m%d", n_now))
	then
		n_notifyFlag = t_activity.notify_flag
	end
	
	-- ABTest（原本拍脸的用户组一半拍脸，一半不拍脸）
	if n_notifyFlag == 1 and t_conf.s_ABTest and string_match(t_conf.s_ABTest, "^%s*$") == nil then
		n_bucketId, n_res = mis_data.t_ABTestSDK.getABTestExp(t_conf.s_ABTest, n_uin)
		if not n_bucketId or n_res ~= 1 then
			n_notifyFlag = 0
			log.day_list("daily_sign_ab","daily_sign_status",n_uin,'ABTest不中',uu.to_str(n_bucketId),uu.to_str(n_res))
		else
			log.day_list("daily_sign_ab","daily_sign_status",n_uin,'ABTest中',uu.to_str(n_bucketId),uu.to_str(n_res))
		end
	end

	n_code, s_desc = t_user:set_daily_sign_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("daily_sign", "daily_sign_status", "save user data error", n_uin, uu.to_str(n_code), uu.to_str(s_desc), uu.to_str(t_userData))
		return n_code, s_desc
	end

	t_resp = {
		low_active = t_activity.low_active,
		notice_flag = n_notifyFlag,
		week_sign = t_userData.week_sign,
		sign_card_count = t_userData.sign_card_count,
		sign_card_count_max = t_userData.sign_card_count_max
	}
	
	-- log.day_list("daily_sign", "daily_sign_status", "ok", n_uin, uu.to_str(t_resp), uu.to_str(t_userData))
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：每日签到
-- 返回：n					状态码
--		ts 					描述
this.daily_sign = function()
	local t_params 		= ngx.ctx.t_params
	local n_uin 		= t_params.uin
	local n_weekDay 	= tonumber(t_params.week_day)
	local t_signConf	= mis_data.t_daily_sign.t_conf
	local n_now 		= mis_data.offset_now_v2(t_signConf)
	local t_map 		= mis_config.t_daily_sign_map
	local n_code, s_desc, t_user, t_userData, t_resp
	local n_costBean, t_tmpConf, t_award_list, s_items
	local n_start, n_stop, n_unit, t_recommend_maps

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_daily_sign_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user daily_sign data error'
	end

	-- 没有活跃数据
	if t_userData.activity == nil then
		log.day_list("daily_sign", "daily_sign", "no activity data", n_uin, uu.to_str(t_userData))
		return t_retCode.n_OPER_ERR, 'no activity data'
	end

	-- 等于nil表示当天签到
	if n_weekDay == nil then
		n_weekDay = tonumber(os_date("%w", n_now))
		if n_weekDay == 0 then
			n_weekDay = 7
		end
	else
		-- 是否还有补签卡
		if t_userData.sign_card_count <= 0 then
			log.day_list("daily_sign", "daily_sign", "sign card empty", n_uin, uu.to_str(t_userData))
			return t_retCode.n_OPER_ERR, 'sign card empty'
		end

		-- 扣一张补签卡
		t_userData.sign_card_count = t_userData.sign_card_count - 1

		-- 补签
		if t_userData.activity.is_identified == 1 and t_userData.activity.is_adult == 1 then
			t_tmpConf = t_signConf.t_adult_sign
		else
			t_tmpConf = t_signConf.t_under_age_sign
		end
		
		n_costBean = t_tmpConf.sign_cost_bean[n_weekDay]

		-- 参数错误
		if not n_costBean then
			log.day_list("daily_sign", "daily_sign", "no cost data", n_uin, uu.to_str(n_weekDay), uu.to_str(t_tmpConf))
			return t_retCode.n_OPER_ERR, 'no cost data'
		end
	end

	-- 已签到
	if t_userData.week_sign[n_weekDay] == 1 then
		log.day_list("daily_sign", "daily_sign", "already sign", n_uin, uu.to_str(n_weekDay), uu.to_str(t_userData))
		return t_retCode.n_OPER_ERR, 'already sign'
	end

	-- 扣迷你豆
	if n_costBean and n_costBean > 0 then
		n_code, s_desc = mis_bridge.cost_money(t_params.uin, nil, n_costBean, mis_config.t_costType.n_BEAN, 'daily_sign_ex'
			, mis_common.table_to_json({aname = 'daily_sign_ex', week_day = n_weekDay, now = n_now}))
		if n_code ~= t_retCode.n_OK then
			log.day_list("daily_sign", "daily_sign", "cost bean error", n_uin, n_code, uu.to_str(s_desc), uu.to_str(n_weekDay), uu.to_str(t_userData))
			return n_code, s_desc
		end
	end

	-- 签到/补签成功
	t_userData.week_sign[n_weekDay] = 1

	-- 发放奖励
	t_tmpConf = t_signConf.t_sign_award[n_weekDay]
	t_award_list = {{id = t_tmpConf.id, num = t_tmpConf.num}}
	n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_award_list, mis_config.t_workType.s_DAILY_SIGN, 'daily_sign')
	if n_code ~= t_retCode.n_OK then
		log.day_list("daily_sign", "daily_sign", "award error", n_uin, n_code, uu.to_str(s_desc), uu.to_str(s_items))
		return n_code, s_desc
	end

	-- 更新用户数据
	n_code, s_desc = t_user:set_daily_sign_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("daily_sign", "daily_sign", "save user data error", n_uin, uu.to_str(n_code), uu.to_str(s_desc), uu.to_str(t_userData))
		return n_code, s_desc
	end

	-- 推荐地图（全部地图分7份，每次从其中一份抽取3张）
	t_recommend_maps = mis_calcu.segment_select_random(t_map, 7, n_weekDay, 3)

	t_resp = {
		week_sign = t_userData.week_sign,
		sign_card_count = t_userData.sign_card_count,
		recommend_maps = t_recommend_maps,
		award_list = t_award_list
	}
	
	-- log.day_list("daily_sign", "daily_sign_status", "ok", n_uin, uu.to_str(t_resp), uu.to_str(t_userData), uu.to_str(t_params.week_day))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务领奖
-- 返回：n					状态码
--		ts 					描述
local novice_task_getaward_core = function(t_userData, n_taskID, n_subTaskId, n_mode, t_mission, t_award)
	local t_params 			= ngx.ctx.t_params
	local n_nowTime 		= mis_data.get_server_time()
	local t_subTask

	if not(n_taskID and n_mode and t_userData and mis_uu.tableNotEmpty(t_userData) and
			t_userData.tasks and mis_uu.tableNotEmpty(t_userData.tasks) and
			t_mission and mis_uu.tableNotEmpty(t_mission) and
			t_mission.t_bonus and mis_uu.tableNotEmpty(t_mission.t_bonus)) then
		mis_log.day("novice_task_error", "novice_task_getaward_core param error|" .. t_params.uin .. "|" .. uu.to_str(n_taskID) .. "|" .. uu.to_str(n_subTaskId) .. "|" .. uu.to_str(n_mode))
		return t_retCode.n_PARAM_ERR, "param error"
	end

	-- 更新领奖状态
	t_subTask = t_userData.tasks[n_taskID][n_subTaskId]
	if not t_subTask then
		mis_log.day("novice_task_error", "novice_task_getaward_core Invalid reward|" .. t_params.uin .. "|" .. uu.to_str(n_taskID) .. "|" .. uu.to_str(n_mode) .. "|" .. uu.to_str(n_subTaskId))
		return t_retCode.n_OPER_ERR, 'task id invalid'
	end

	if t_subTask.status == 1 then
		t_subTask.status 		= 2
		t_subTask.mode			= n_mode				-- 0 手动领奖；1自动领奖
		--t_subTask.refreshTime	= n_nowTime
		t_subTask.rewardTime 	= n_nowTime

		-- 奖励
		if t_award then
			for k, v in pairs(t_mission.t_bonus) do
				table_insert(t_award, {id = v.s_itemId, num = v.n_num})
			end
		end
	else
		mis_log.day("novice_task_error", "novice_task_getaward_core task is not finish status|" .. t_params.uin .. "|" .. uu.to_str(n_taskID) .. "|" .. uu.to_str(n_subTaskId) .. "|" .. uu.to_str(n_mode) .. "|" .. uu.to_str(t_subTask.status))
		return t_retCode.n_OPER_ERR, 'task is not finish status'
	end

	return t_retCode.n_OK, t_userData
end

--------------------------------------------------------------
-- 说明：新手任务过滤新增任务类型，旧端不展示新增任务
local filter_show_event = function(t_userData, t_taskList, n_taskID)
	local t_params 			= ngx.ctx.t_params
	local n_eventVer		= tonumber(t_params.event_ver)
	local t_newEventConf	= uu.table_value_copy(mis_data.t_novice_task.t_conf.t_newEventConf)
	local t_newEvent		= {}
	local t_temp			= {}

	if not(t_userData and mis_uu.tableNotEmpty(t_userData)) then
		return false
	end
	if not (n_taskID and t_taskList[n_taskID] and t_taskList[n_taskID].t_mission) then
		return false
	end

	-- 兼容旧端 新增任务类型不显示
	if t_newEventConf and t_newEventConf.new_event and t_newEventConf.show_event then
		if n_eventVer then
			for _, event in pairs(t_newEventConf.show_event[n_eventVer] or {}) do
				for k, v in pairs(t_newEventConf.new_event) do
					if event == v then
						table.remove(t_newEventConf.new_event, k)
						break
					end
				end
			end
		end
		t_newEvent = t_newEventConf.new_event
	end

	-- 获取子任务配置
	t_temp = t_taskList[n_taskID].t_mission

	for _, n_event in pairs(t_newEvent or {}) do
		local t_mission	= t_temp[n_event] or {}
		for k, v in pairs(t_mission) do
			if v.n_subTaskId and t_userData.tasks[n_taskID][v.n_subTaskId] then
				t_userData.tasks[n_taskID][v.n_subTaskId] = nil
			end
		end
	end
end

--------------------------------------------------------------
-- 说明：新手任务状态 查询/更新
-- 返回：n					状态码
--		ts 					描述
local novice_task_status_core = function(t_userData, t_taskList, n_getAwardMod)
	local n_nowtime 		= mis_data.get_server_time()
	local t_award, t_awardClassify, t_awardAll = {}, {}, {}

	if t_userData.tasks == nil then
		t_userData.tasks	= {}
	end

	-- 通过配置表刷新玩家任务
	for k, v in pairs(t_taskList) do
		t_userData.tasks[k] = t_userData.tasks[k] or {}

		for k2, v2 in pairs(v.t_mission) do

			for k3, v3 in pairs(v2) do
				local n_taskId		= v3.n_subTaskId
				local t_task 		= t_userData.tasks[k][n_taskId]
				local b_update  	= false
				local n_status		= 0
				local n_refreshTime = 0
				local n_progress	= 0

				if t_task then
					-- 刷新任务
					if v3.b_daily and mis_common.is_another_day(t_task.refreshTime, n_nowtime) then
						b_update = true
					end
					if v3.b_weekly and mis_common.is_another_week(t_task.refreshTime, n_nowtime) then
						b_update = true
					end
					-- 自动领取奖励
					if t_task.status == 1 and v3.t_bonus and mis_uu.tableNotEmpty(v3.t_bonus) then
						if n_getAwardMod == mis_config.t_missionGetAward.ALL 
						or (n_getAwardMod == mis_config.t_missionGetAward.EXPIRE and b_update) then
							t_award = {}
							novice_task_getaward_core(t_userData, k, n_taskId, 1, v3, t_award)
							t_awardClassify[n_taskId] = t_award
							for i = 1, #t_award do
								table_insert(t_awardAll, t_award[i])
							end
						end
						t_task = t_userData.tasks[k][n_taskId]
					end
				end

				-- 更新任务
				if not t_task or b_update == true then
					t_task = { progress = n_progress, status = n_status, refreshTime = n_refreshTime, rewardTime = 0, mode = 0 }
				end
				t_userData.tasks[k][n_taskId] =  t_task
			end
		end
	end

	-- 清除已下线活动数据
	for k, v in pairs(t_userData.tasks) do
		if not t_taskList[k] then
			v = nil
			t_userData.tasks[k] = nil
		end
	end

	-- 兼容旧端 新增任务类型不显示
	filter_show_event(t_userData, t_taskList, 1)

	-- 客户端界面显示
	local t_tasks = {}
	for k, v in pairs(t_userData.tasks) do
		t_tasks[k] = {}
		for k2, v2 in pairs(v) do
			t_tasks[k][k2] = { progress = v2.progress, status = v2.status }
		end
	end

	return t_retCode.n_OK, t_tasks, t_awardAll, t_awardClassify
end

--------------------------------------------------------------
-- 说明：新手任务事件
-- 返回：n					状态码
--		ts 					描述
local novice_task_event_core = function(t_userData, t_taskList, n_taskID, n_event, n_value)
	local n_nowTime 		= mis_data.get_server_time()
	local t_temp, t_mission = {}, {}

	if not(t_userData and mis_uu.tableNotEmpty(t_userData)) then
		return t_retCode.n_PARAM_ERR, "param error"
	end

	if not(n_taskID and n_value) then
		return t_retCode.n_PARAM_ERR, "param error"
	end

	if not (n_taskID and t_taskList[n_taskID] and t_taskList[n_taskID].t_mission) then
		mis_log.day("novice_task_error", "novice_task_event_core type error|" .. n_taskID .. '|' .. n_event)
		return t_retCode.n_PARAM_ERR, "task type error"
	end

	-- 获取子任务配置
	t_temp = t_taskList[n_taskID].t_mission
	for k, v in pairs(t_temp) do
		if k == n_event then
			t_mission = v
			break
		end
	end

	if not (t_mission and mis_uu.tableNotEmpty(t_mission)) then
		mis_log.day("novice_task_error", "concert_event_core mission not exist|" .. n_taskID .. '|' .. n_event)
		return t_retCode.n_PARAM_ERR, "mission not exist"
	end

	-- 更新任务进度、状态
	for k, v in pairs(t_mission) do
		local t_task = t_userData.tasks[n_taskID][v.n_subTaskId]
		if not t_task then
			t_task = {status = 0, progress = 0, refreshTime = 0 }
		end

		-- 更新进度
		if t_task.status == 0 then			
			-- 获得指定道具类型的任务
			if n_event == 30 then
				if v.n_gain_item == n_value then
					t_task.progress	= t_task.progress + 1
					t_task.refreshTime 	= n_nowTime
				end
			else
				t_task.progress = t_task.progress + n_value
				t_task.refreshTime 	= n_nowTime
			end
		end
		-- 任务完成
		if t_task.status == 0 and v.n_target and t_task.progress >= v.n_target then
			t_task.status 		= 1
			t_task.progress		= v.n_target
			t_task.refreshTime 	= n_nowTime

			-- 埋点数据
			local t_params = ngx.ctx.t_params
			mis_log.remote_pure_day("novice_task_getaward", mis_common.table_to_json({
				key = "mission_system";
				ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
				uin = t_params.uin;
				time = mis_data.get_server_time();
				country = t_params.country or 'nil';
				apiid = t_params.apiid or 'nil';
				ver = t_params.ver or 'nil';
				lang = t_params.lang or 'nil';
				labelid = 9;
				taskid = v.n_subTaskId;
				bonusid = {};
				action = "complete";
			}))
		end
		t_userData.tasks[n_taskID][v.n_subTaskId] = t_task
	end

	return t_retCode.n_OK, t_userData
end

--------------------------------------------------------------
-- 说明：检测指定新手任务事件是否完成
-- 返回：n					状态码
--		ts 					描述
local check_task_event_trigger = function(t_userData, t_taskList, n_taskID, n_event)
	local t_temp, t_mission = {}, {}
	local b_bindTrigger 	= false

	if not(t_userData and mis_uu.tableNotEmpty(t_userData)) then
		return false
	end
	if not (n_taskID and t_taskList[n_taskID] and t_taskList[n_taskID].t_mission) then
		return false
	end

	-- 获取子任务配置
	t_temp = t_taskList[n_taskID].t_mission
	for k, v in pairs(t_temp) do
		if k == n_event then
			t_mission = v
			break
		end
	end

	if not (t_mission and mis_uu.tableNotEmpty(t_mission)) then
		return false
	end

	b_bindTrigger = true

	for k, v in pairs(t_mission) do
		local t_task = t_userData.tasks[n_taskID][v.n_subTaskId]

		if t_task and v.n_target and t_task.progress >= v.n_target then
			b_bindTrigger = false
		else
			b_bindTrigger = true
			break
		end
	end
	--mis_log.day("task_trigger","check_task_event_trigger|" .. ngx.ctx.t_params.uin .. '|' .. (b_bindTrigger and 'true' or 'false'))
	return b_bindTrigger
end

-- 计算已完成任务数量
local count_finish_task = function(t_tasks)
	if not t_tasks then
		return 0
	end
	local n_count = 0
	for k, v in pairs(t_tasks) do
		for k2, v2 in pairs(v) do
			if v2.status == 1 or v2.status == 2 then
				n_count = n_count + 1
			end
		end
	end
	return n_count
end

-- 计算已完成未领取任务数量
local count_can_get_reward_task = function(t_tasks)
	if not t_tasks then
		return 0
	end
	local n_count = 0
	for k, v in pairs(t_tasks) do
		for k2, v2 in pairs(v) do
			if v2.status == 1 then
				n_count = n_count + 1
			end
		end
	end
	return n_count
end

-- 获取新手通知的推送时间
local get_novice_task_push_time = function(t_pushConf)
	local date = os_date("*t")
	date.hour = t_pushConf.t_send_time.hour
	date.min = t_pushConf.t_send_time.min
	date.sec = 0
	return (os_time(date) + t_pushConf.n_send_delay) * 1000
end

-- 新手推送前置条件检查
local novice_check_to_push = function(n_uin, t_pushConf)
	local now = mis_data.get_server_time()
	if now < t_pushConf.n_start_time then
		mis_log.day("novice_task_error","novice push not start|" .. n_uin)
		return false
	end
	-- 测试白名单
	if mis_uu.tableNotEmpty(t_pushConf.t_test_uin) 
	and t_pushConf.t_test_uin[n_uin] ~= 1 then
		mis_log.day("novice_task_error","novice push not in white list|" .. n_uin)
		return false
	end
	return true
end

--------------------------------------------------------------
-- 说明：新手任务签到奖励领取
local novice_sign_getaward = function(t_dailySign, t_conf)
	local t_params 		= ngx.ctx.t_params
	local n_nowtime 	= mis_data.get_server_time()
	local n_signCount	= t_dailySign.sign_count
	local t_signAward 	= t_conf.t_dailySignAward or {}
	local t_award		= t_signAward[n_signCount+1]
	local t_bonus		= {}
	local n_code, s_desc, s_items

	if not t_award then
		return t_retCode.n_OPER_ERR, 'sign award not exist'
	end

	for k, v in pairs(t_award) do
		table_insert(t_bonus, {id = v.itemId, num = tonumber(v.num)})
	end

	-- 发奖
	if #t_bonus > 0 then
		n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_bonus, mis_config.t_workType.s_NOVICE_TASK, 'novice_sign')
		if n_code ~= t_retCode.n_OK then
			mis_log.day("novice_task_error", "novice_sign_getaward add_items error|" .. t_params.uin .. "|" .. uu.to_str(s_desc) .. "|" .. uu.to_str(s_items))
			return n_code, s_desc
		end
	end

	n_signCount				= n_signCount + 1
	t_dailySign.update_time = n_nowtime
	t_dailySign.sign_count 	= n_signCount
	t_dailySign.sign_data	= t_dailySign.sign_data or {}
	t_dailySign.sign_data[n_signCount] = {
		ctime = n_nowtime,
		bonus = t_bonus
	}

	--埋点数据
	mis_log.remote_pure_day("novice_sign_getaward", mis_common.table_to_json({
		key 	= "mission_system";
		ip 		= t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin 	= t_params.uin;
		time 	= n_nowtime;
		country = t_params.country or 'nil';
		apiid 	= t_params.apiid or 'nil';
		ver 	= t_params.ver or 'nil';
		lang 	= t_params.lang or 'nil';
		bonus 	= t_bonus;
		total	= n_signCount;
	}))

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：新用户首次进入商城领取奖励
local novice_newuser_getaward = function(t_newUserData, t_conf)
	local t_params 		= ngx.ctx.t_params
	local n_nowtime 	= mis_data.get_server_time()
	local t_signAward 	= t_conf.t_newUserAward or {}
	local t_bonus		= {}
	local n_code, s_desc, s_items

	for k, v in pairs(t_signAward) do
		table_insert(t_bonus, {id = v.itemId, num = tonumber(v.num)})
	end

	-- 发奖
	if #t_bonus > 0 then
		n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_bonus, mis_config.t_workType.s_NOVICE_TASK, 'Newplayer_StoreReward')
		if n_code ~= t_retCode.n_OK then
			mis_log.day("novice_task_error", "novice_newuser_getaward add_items error|" .. t_params.uin .. "|" .. uu.to_str(s_desc) .. "|" .. uu.to_str(s_items))
			return n_code, s_desc
		end
	end

	t_newUserData.state = 1
	t_newUserData.ctime = n_nowtime
	t_newUserData.bonus	= t_bonus

	--埋点数据
	mis_log.remote_pure_day("novice_newuser_getaward", mis_common.table_to_json({
		key 	= "mission_system";
		ip 		= t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin 	= t_params.uin;
		time 	= n_nowtime;
		country = t_params.country or 'nil';
		apiid 	= t_params.apiid or 'nil';
		ver 	= t_params.ver or 'nil';
		lang 	= t_params.lang or 'nil';
		bonus 	= t_bonus;
	}))

	return t_retCode.n_OK
end
--------------------------------------------------------------
-- 说明：新手任务 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_novice_task = function()
	local t_params  		= ngx.ctx.t_params
	local t_novice_task		= mis_data.t_novice_task
	local n_nowtime 		= mis_data.get_server_time()

	if t_novice_task.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'novice_task disable'
	end

	-- 活动有效期间
	if n_nowtime < t_novice_task.t_conf.n_startTime or n_nowtime > t_novice_task.t_conf.n_endTime then
		return t_retCode.n_OPER_ERR, 'not within the validity period'
	end

	-- 渠道控制
	if mis_uu.tableNotEmpty(t_novice_task.t_conf.apiids) then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)

		for _, v in pairs(t_novice_task.t_conf.t_apiids) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if not b_valid_apiid then
			return t_retCode.n_OPER_ERR, 'apiid is invalid'
		end
	end

	-- 版本号控制
	local n_l = mis_common.version_to_number(t_params.ver or 0)
	local n_r = t_novice_task.t_conf.n_version_min
	if n_l < n_r then
		return t_retCode.n_OPER_ERR, 'version too low'
	end

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：新手任务状态
-- 返回：n					状态码
--		ts 					描述
this.novice_task_status = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local s_workType		= mis_config.t_workType.s_NOVICE_TASK
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_nowtime 		= mis_data.get_server_time()
	local n_pushTime		= get_novice_task_push_time(t_conf.t_push)
	local b_canPush			= novice_check_to_push(n_uin, t_conf.t_push)
	local n_code, s_desc, t_user, t_userData
	local t_resp, t_tasks, t_expireAward, t_dailySign
	local n_finishBefore, n_finishAfter
	local s_scheme

	if t_params.platform == "android" then
		s_scheme = mis_config.s_mobpush_dplink_novice_task_android
	elseif t_params.platform == "ios" then
		s_scheme = mis_config.s_mobpush_dplink_novice_task_ios
	elseif t_params.platform == "pc" then
		-- pass
	elseif t_params.platform ~= nil then
		mis_log.day("novice_task_error","unknown platform|" .. t_params.uin .. "|" .. uu.to_str(t_params.platform))
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_task data error'
	end

	-- 未开启新手任务
	if t_userData.notice_flag ~= 1 then
		if not t_userData.accept_end_time then
			t_userData.accept_end_time = n_nowtime + t_conf.n_pending_duration
		end

		if n_nowtime > t_userData.accept_end_time then
			return t_retCode.n_OPER_ERR, "accept expire"
		end

		-- mobpush推送（accept_push_time：非空表示已注册推送）
		if t_userData.accept_push_time == nil and b_canPush then
			n_code, s_desc = mis_bridge.modpush_send(
				n_uin, 
				mis_config.s_mobpush_flag_novice_task_accept, 
				mis_config.s_mobpush_novice_task_mergePushId,
				n_pushTime,
				s_scheme,
				mis_config.s_mobpush_novice_task_region,
				mis_config.s_mobpush_novice_task_language
			)
			if n_code == t_retCode.n_OK then
				t_userData.accept_push_bid = s_desc.data.batchId
				t_userData.accept_push_time = n_pushTime
				mis_log.day("novice_task","modpush_send accept_push|" 
					.. t_params.uin 
					.. '|' .. uu.to_str(s_desc.data.batchId)
					.. "|" .. uu.to_str(t_userData.accept_push_time)
					.. '|' .. uu.to_str(s_scheme))
			end
		end
	
		n_code, s_desc   = t_user:set_novice_task_data(t_userData)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end

		t_resp = {
			tasks = {},
			notice_flag = 0,
			expire_award = {},
			notice_end_time = 0,
			accept_end_time = t_userData.accept_end_time or 0,
			final_award_progress = 0,
			final_award_status = 0,
			final_award_select = 0,
		}

		return t_retCode.n_OK, t_resp
	end

	if n_nowtime > t_userData.notice_end_time then
		return t_retCode.n_OPER_ERR, "expire"
	end

	-- 刷新任务
	n_code, t_tasks, t_expireAward = novice_task_status_core(t_userData, t_conf.t_taskList, mis_config.t_missionGetAward.EXPIRE)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	
	if mis_uu.tableNotEmpty(t_expireAward) then
		t_userData.expire_award = t_expireAward
	end
	
	-- 登录任务更新
	n_finishBefore = count_finish_task(t_userData.tasks)
	n_code, s_desc = novice_task_event_core(t_userData, t_conf.t_taskList, 1, 18, 1)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("novice_task_error","novice_task_status login error|" .. t_params.uin .. '|' .. uu.to_str(n_code))
	end

	-- 检测绑定手机号任务，未完成手动触发
	if check_task_event_trigger(t_userData, t_conf.t_taskList, 1, 60) and
			mis_bridge.query_bind_phone(t_params.uin) then
		n_code, s_desc = novice_task_event_core(t_userData, t_conf.t_taskList, 1, 60, 1)
		if n_code ~= t_retCode.n_OK then
			mis_log.day("novice_task_error","novice_task_status bind error|" .. t_params.uin .. '|' .. uu.to_str(n_code))
		end
	end

	n_finishAfter = count_finish_task(t_userData.tasks)

	-- 更新大奖进度
	if t_userData.final_award_status == 0 then
		t_userData.final_award_progress = t_userData.final_award_progress + (n_finishAfter - n_finishBefore)
		if t_userData.final_award_progress >= t_conf.n_finalAwardTarget then		
			t_userData.final_award_progress = t_conf.n_finalAwardTarget
			t_userData.final_award_status = 1		-- 大奖完成
		end
	end

	-- 判断是否推送领奖提示（未曾推送过且有未领取奖励任务）
	-- getaward_push_time == 0 表示还未推送就被取销了，也算未曾推送过
	-- getaward_push_time 不是nil也不是0，表示已经推送过或者已经注册推送
	if (t_userData.getaward_push_time or 0) == 0
	and count_can_get_reward_task(t_userData.tasks) > 0 
	and b_canPush then
		-- T + n推送
		n_code, s_desc = mis_bridge.modpush_send(
			n_uin, 
			mis_config.s_mobpush_flag_novice_task_getaward, 
			mis_config.s_mobpush_novice_task_mergePushId,
			n_pushTime,
			s_scheme,
			mis_config.s_mobpush_novice_task_region,
			mis_config.s_mobpush_novice_task_language
		)
		if n_code == t_retCode.n_OK then
			t_userData.getaward_push_bid = s_desc.data.batchId
			t_userData.getaward_push_time = n_pushTime
			mis_log.day("novice_task","modpush_send getaward_push 1|" 
				.. t_params.uin 
				.. '|' .. uu.to_str(s_desc.data.batchId) 
				.. "|" .. uu.to_str(t_userData.getaward_push_time)
				.. '|' .. uu.to_str(s_scheme))
		end
	end

	-- 判断是否推送领大奖提示
	if (t_userData.final_award_push_time or 0) == 0
	and t_userData.final_award_status == 1 
	and b_canPush then
		-- T + n推送
		n_code, s_desc = mis_bridge.modpush_send(
			n_uin, 
			mis_config.s_mobpush_flag_novice_task_getaward_final, 
			mis_config.s_mobpush_novice_task_mergePushId,
			n_pushTime,
			s_scheme,
			mis_config.s_mobpush_novice_task_region,
			mis_config.s_mobpush_novice_task_language
		)
		if n_code == t_retCode.n_OK then
			t_userData.final_award_push_bid = s_desc.data.batchId
			t_userData.final_award_push_time = n_pushTime
			mis_log.day("novice_task","modpush_send final_award_push 1|" 
				.. t_params.uin 
				.. '|' .. uu.to_str(s_desc.data.batchId)
				.. "|" .. uu.to_str(t_userData.final_award_push_time)
				.. '|' .. uu.to_str(s_scheme))
		end
	end

	-- 累计签到任务
	if t_userData.daily_sign then
		local n_validSign 	= 0
		local n_signCount	= t_userData.daily_sign.sign_count or 0
		local t_signAward 	= t_conf.t_dailySignAward or {}
		if n_signCount < #t_signAward and t_userData.daily_sign.update_time and
			mis_common.is_another_day(t_userData.daily_sign.update_time, n_nowtime) then
			n_validSign = 1
		end

		t_dailySign = { sign_count = n_signCount, sign_state = n_validSign }
	end
	
	n_code, s_desc   = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	t_tasks = {}
	for k, v in pairs(t_userData.tasks) do
		t_tasks[k] = {}
		for k2, v2 in pairs(v) do
			t_tasks[k][k2] = { progress = v2.progress, status = v2.status }
		end
	end

	t_resp = {
		tasks = t_tasks[1],
		notice_flag = t_userData.notice_flag or 0,
		expire_award = t_expireAward or {},
		abtest_new = 1,
		notice_end_time = t_userData.notice_end_time or 0,
		accept_end_time = t_userData.accept_end_time or 0,
		final_award_progress = t_userData.final_award_progress,
		final_award_status = t_userData.final_award_status,
		final_award_select = t_userData.final_award_select,
		daily_sign = t_dailySign,
	}
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务状态
-- 返回：n					状态码
--		ts 					描述
this.novice_task_accept = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local n_select			= t_params.award_select
	local s_workType		= mis_config.t_workType.s_NOVICE_TASK
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_nowtime 		= mis_data.get_server_time()
	local n_pushTime 		= get_novice_task_push_time(t_conf.t_push)
	local b_canPush			= novice_check_to_push(n_uin, t_conf.t_push)

	local n_code, s_desc, t_user, t_userData
	local t_resp, t_tasks, t_award, t_awardAdd, s_items
	local n_finishBefore, n_finishAfter     
	local s_scheme

	if t_params.platform == "android" then
		s_scheme = mis_config.s_mobpush_dplink_novice_task_android
	elseif t_params.platform == "ios" then
		s_scheme = mis_config.s_mobpush_dplink_novice_task_ios
	elseif t_params.platform == "pc" then
		-- pass
	elseif t_params.platform ~= nil then
		mis_log.day("novice_task_error","unknown platform|" .. t_params.uin .. "|" .. uu.to_str(t_params.platform))
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_task data error'
	end

	-- 重复开启
	if t_userData.notice_flag == 1 then
		mis_log.day("novice_task_error", "novice_task_accept repeate|" .. '|' .. n_uin .. '|' .. uu.to_str(t_userData))
		return t_retCode.n_OPER_ERR, "already accept"
	end

	t_award = t_conf.t_trySuitAward[n_select]
	if not mis_uu.tableNotEmpty(t_award) then
		mis_log.day("novice_task_error", "novice_task_accept select error|" .. '|' .. n_uin .. '|' .. uu.to_str(n_select))
		return t_retCode.n_OPER_ERR, "select error"
	end
	
	t_awardAdd = {}
	for i = 1, #t_award do
		table_insert(t_awardAdd, {id = t_award[i].itemId, num = t_award[i].num})
	end

	-- 刷新任务
	n_code, t_tasks = novice_task_status_core(t_userData, t_conf.t_taskList)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	
	t_userData.notice_flag = 1				-- 更新开启标识
	t_userData.notice_end_time = n_nowtime + t_conf.n_duration
	t_userData.final_award_progress = 0		-- 大奖进度
	t_userData.final_award_status = 0		-- 大奖状态
	t_userData.final_award_select = 0		-- 大奖选择
	t_userData.accept_award_select = n_select -- 试穿选择
	
	-- 登录任务更新
	n_finishBefore = count_finish_task(t_userData.tasks)
	n_code, s_desc = novice_task_event_core(t_userData, t_conf.t_taskList, 1, 18, 1)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("novice_task_error","novice_task_status login error|" .. t_params.uin .. '|' .. uu.to_str(n_code))
	end

	-- 检测绑定手机号任务，未完成手动触发
	if check_task_event_trigger(t_userData, t_conf.t_taskList, 1, 60) and
			mis_bridge.query_bind_phone(t_params.uin) then
		n_code, s_desc = novice_task_event_core(t_userData, t_conf.t_taskList, 1, 60, 1)
		if n_code ~= t_retCode.n_OK then
			mis_log.day("novice_task_error","novice_task_status bind error|" .. t_params.uin .. '|' .. uu.to_str(n_code))
		end
	end

	n_finishAfter = count_finish_task(t_userData.tasks)

	-- 更新大奖进度
	if t_userData.final_award_status == 0 then
		t_userData.final_award_progress = t_userData.final_award_progress + (n_finishAfter - n_finishBefore)
		if t_userData.final_award_progress >= t_conf.n_finalAwardTarget then		
			t_userData.final_award_progress = t_conf.n_finalAwardTarget
			t_userData.final_award_status = 1		-- 大奖完成
		end
	end

	-- 判断是否推送领奖提示（未曾推送过且有未领取奖励任务）
	-- getaward_push_time == 0 表示还未推送就被取销了，也算未曾推送过
	-- getaward_push_time 不是nil也不是0，表示已经推送过或者已经注册推送
	if (t_userData.getaward_push_time or 0) == 0
	and count_can_get_reward_task(t_userData.tasks) > 0 
	and b_canPush then
		-- T + n推送
		n_code, s_desc = mis_bridge.modpush_send(
			n_uin, 
			mis_config.s_mobpush_flag_novice_task_getaward, 
			mis_config.s_mobpush_novice_task_mergePushId,
			n_pushTime,
			s_scheme,
			mis_config.s_mobpush_novice_task_region,
			mis_config.s_mobpush_novice_task_language
		)
		if n_code == t_retCode.n_OK then
			t_userData.getaward_push_bid = s_desc.data.batchId
			t_userData.getaward_push_time = n_pushTime
			mis_log.day("novice_task","modpush_send getaward_push 2|" 
				.. t_params.uin 
				.. '|' .. uu.to_str(s_desc.data.batchId)
				.. '|' .. uu.to_str(t_userData.getaward_push_time)
				.. '|' .. uu.to_str(s_scheme))
		end
	end

	-- 判断是否推送领大奖提示
	if (t_userData.final_award_push_time or 0) == 0
	and t_userData.final_award_status == 1 
	and b_canPush then
		-- T + n推送
		n_code, s_desc = mis_bridge.modpush_send(
			n_uin, 
			mis_config.s_mobpush_flag_novice_task_getaward_final, 
			mis_config.s_mobpush_novice_task_mergePushId,
			n_pushTime,
			s_scheme,
			mis_config.s_mobpush_novice_task_region,
			mis_config.s_mobpush_novice_task_language
		)
		if n_code == t_retCode.n_OK then
			t_userData.final_award_push_bid = s_desc.data.batchId
			t_userData.final_award_push_time = n_pushTime
			mis_log.day("novice_task","modpush_send final_award_push 2|" 
				.. t_params.uin 
				.. '|' .. uu.to_str(s_desc.data.batchId)
				.. '|' .. uu.to_str(t_userData.final_award_push_time)
				.. '|' .. uu.to_str(s_scheme))
		end
	end

	-- 判断是否取消推送接新手任务提示
	-- accept_push_time == 0 表示还未推送就被取销了，也算未曾推送过
	-- accept_push_time 不是nil也不是0，表示已经推送过或者已经注册推送
	if t_userData.accept_push_time ~= nil
	and (n_nowtime * 1000) < t_userData.accept_push_time
	and t_userData.accept_push_bid ~= nil then
		t_userData.accept_push_time = 0
		mis_bridge.modpush_cancel(t_params.uin, t_userData.accept_push_bid, mis_config.s_mobpush_novice_task_mergePushId)
		mis_log.day("novice_task","modpush_cancel accept_push|" .. t_params.uin .. '|' .. uu.to_str(t_userData.accept_push_bid))
	end

	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_awardAdd, s_workType, 'novice_task_final')
	if n_code ~= t_retCode.n_OK then
		mis_log.day("novice_task_error", "novice_task_accept add_items error|" .. t_params.uin .. "|" .. n_code .. "|" .. uu.to_str(s_desc) .. "|" .. uu.to_str(s_items))
		return n_code, s_desc
	end

	t_tasks = {}
	for k, v in pairs(t_userData.tasks) do
		t_tasks[k] = {}
		for k2, v2 in pairs(v) do
			t_tasks[k][k2] = { progress = v2.progress, status = v2.status }
		end
	end

	t_resp = {
		tasks = t_tasks[1],
		notice_flag = t_userData.notice_flag or 0,
		notice_end_time = t_userData.notice_end_time or 0,
		final_award_progress = t_userData.final_award_progress,
		final_award_status = t_userData.final_award_status,
		final_award_select = t_userData.final_award_select,
	}
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务事件
-- 返回：n					状态码
--		ts 					描述
this.novice_task_event = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local n_event			= t_params.event
	local n_value			= tonumber(t_params.value)
	local s_workType		= mis_config.t_workType.s_NOVICE_TASK
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_nowtime 		= mis_data.get_server_time()
	local n_pushTime		= get_novice_task_push_time(t_conf.t_push)
	local b_canPush			= novice_check_to_push(n_uin, t_conf.t_push)
	local n_code, s_desc, t_user, t_userData
	local t_resp, n_finishBefore, n_finishAfter
	local s_scheme

	if t_params.platform == "android" then
		s_scheme = mis_config.s_mobpush_dplink_novice_task_android
	elseif t_params.platform == "ios" then
		s_scheme = mis_config.s_mobpush_dplink_novice_task_ios
	elseif t_params.platform == "pc" then
		-- pass
	elseif t_params.platform ~= nil then
		mis_log.day("novice_task_error","unknown platform|" .. t_params.uin .. "|" .. uu.to_str(t_params.platform))
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_task data error'
	end

	if t_userData.notice_flag ~= 1 then
		return t_retCode.n_OPER_ERR, "not accept"
	end

	if n_nowtime > t_userData.notice_end_time then
		return t_retCode.n_OPER_ERR, "expire"
	end

	n_finishBefore = count_finish_task(t_userData.tasks)
	n_code, s_desc = novice_task_event_core(
		t_userData, 
		t_conf.t_taskList,
		1,
		n_event,
		n_value or 1
	)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	n_finishAfter = count_finish_task(t_userData.tasks)

	if t_userData.final_award_status == 0 then
		t_userData.final_award_progress = t_userData.final_award_progress + (n_finishAfter - n_finishBefore)
		if t_userData.final_award_progress >= t_conf.n_finalAwardTarget then		
			t_userData.final_award_progress = t_conf.n_finalAwardTarget
			t_userData.final_award_status = 1		-- 大奖完成

			--埋点数据
			mis_log.remote_pure_day("novice_task_getaward", mis_common.table_to_json({
				key = "mission_system";
				ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
				uin = t_params.uin;
				time = n_nowtime;
				country = t_params.country or 'nil';
				apiid = t_params.apiid or 'nil';
				ver = t_params.ver or 'nil';
				lang = t_params.lang or 'nil';
				labelid = 9;
				taskid = 99;
				bonusid = {};
				action = "complete";
			}))
		end
	end
	
	-- 判断是否推送领奖提示（未曾推送过且有未领取奖励任务）
	-- getaward_push_time == 0 表示还未推送就被取销了，也算未曾推送过
	-- getaward_push_time 不是nil也不是0，表示已经推送过或者已经注册推送
	if (t_userData.getaward_push_time or 0) == 0
	and count_can_get_reward_task(t_userData.tasks) > 0 
	and b_canPush then
		-- T + n推送
		n_code, s_desc = mis_bridge.modpush_send(
			n_uin, 
			mis_config.s_mobpush_flag_novice_task_getaward, 
			mis_config.s_mobpush_novice_task_mergePushId,
			n_pushTime,
			s_scheme,
			mis_config.s_mobpush_novice_task_region,
			mis_config.s_mobpush_novice_task_language
		)
		if n_code == t_retCode.n_OK then
			t_userData.getaward_push_bid = s_desc.data.batchId
			t_userData.getaward_push_time = n_pushTime
			mis_log.day("novice_task","modpush_send getaward_push 3|" 
				.. t_params.uin 
				.. '|' .. uu.to_str(s_desc.data.batchId)
				.. '|' .. uu.to_str(t_userData.getaward_push_time)
				.. '|' .. uu.to_str(s_scheme))
		end
	end

	-- 判断是否推送领大奖提示
	if (t_userData.final_award_push_time or 0) == 0
	and t_userData.final_award_status == 1 
	and b_canPush then
		-- T + n推送
		n_code, s_desc = mis_bridge.modpush_send(
			n_uin, 
			mis_config.s_mobpush_flag_novice_task_getaward_final, 
			mis_config.s_mobpush_novice_task_mergePushId,
			n_pushTime,
			s_scheme,
			mis_config.s_mobpush_novice_task_region,
			mis_config.s_mobpush_novice_task_language
		)
		if n_code == t_retCode.n_OK then
			t_userData.final_award_push_bid = s_desc.data.batchId
			t_userData.final_award_push_time = n_pushTime
			mis_log.day("novice_task","modpush_send final_award_push 3|" 
				.. t_params.uin 
				.. '|' .. uu.to_str(s_desc.data.batchId)
				.. '|' .. uu.to_str(t_userData.final_award_push_time)
				.. '|' .. uu.to_str(s_scheme))
		end
	end
	
	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	
	t_resp = {
		tasks = t_userData.tasks[1],
		final_award_progress = t_userData.final_award_progress,
		final_award_status = t_userData.final_award_status,
	}
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务每日签到事件
-- 返回：n					状态码
--		ts 					描述
this.novice_sign_event = function()
	local t_params 			= ngx.ctx.t_params
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_nowtime 		= mis_data.get_server_time()

	local n_code, s_desc, t_user, t_userData, t_resp, t_dailySign

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_task data error'
	end

	if t_userData.notice_flag ~= 1 then
		return t_retCode.n_OPER_ERR, "not accept"
	end

	if n_nowtime > t_userData.notice_end_time then
		return t_retCode.n_OPER_ERR, "expire"
	end

	t_userData.daily_sign 	= t_userData.daily_sign or {}
	t_dailySign           	= t_userData.daily_sign
	t_dailySign.update_time = t_dailySign.update_time or 0
	t_dailySign.sign_count  = t_dailySign.sign_count or 0

	if not mis_common.is_another_day(t_dailySign.update_time, n_nowtime) then
		return t_retCode.n_OPER_ERR, "signed in"
	end

	n_code, s_desc = novice_sign_getaward(t_dailySign, t_conf)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	t_resp = {
		daily_sign = { sign_count = t_dailySign.sign_count, sign_state = 0 }
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务领取
-- 返回：n					状态码
--		ts 					描述
this.novice_task_getaward = function()
	local t_params 			= ngx.ctx.t_params
	local t_conf 			= mis_data.t_novice_task.t_conf
	local t_taskList 		= t_conf.t_taskList or {}
	local n_nowtime 		= mis_data.get_server_time()
	local t_mission, t_task, t_temp	= {}, {}, {}
	local n_code, s_desc, t_user, t_userData
	local t_resp, t_award, s_items

	local n_subTaskId		= t_params.task_id
	local n_taskID 			= 1

	if not (n_taskID and t_taskList[n_taskID] and t_taskList[n_taskID].t_mission) then
		mis_log.day("novice_task_error", "novice_task_getaward task conf error|" .. t_params.uin .. "|" .. n_taskID)
		return t_retCode.n_PARAM_ERR, "task conf error"
	end

	-- 获取子任务配置
	t_temp = t_taskList[n_taskID].t_mission
	for k, v in pairs(t_temp) do
		for k2, v2 in pairs(v) do
			if v2.n_subTaskId and n_subTaskId == v2.n_subTaskId then
				t_mission = v2
				break
			end
		end
	end

	if not (t_mission and mis_uu.tableNotEmpty(t_mission)) then
		mis_log.day("novice_task_error", "novice_task_getaward mission not exist|" .. t_params.uin .. "|" .. n_subTaskId)
		return t_retCode.n_PARAM_ERR, "mission not exist"
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_task data error'
	end

	if n_nowtime > t_userData.notice_end_time then
		return t_retCode.n_OPER_ERR, "expire"
	end

	t_award = {}
	n_code, s_desc = novice_task_getaward_core(t_userData, n_taskID, n_subTaskId, 0, t_mission, t_award)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 判断是否取消推送领奖提示（已注册且未推送，没有已完成未领奖任务）
	-- getaward_push_time == 0 表示还未推送就被取销了，也算未曾推送过
	-- getaward_push_time 不是nil也不是0，表示已经推送过或者已经注册推送
	if t_userData.getaward_push_time ~= nil
	and (n_nowtime * 1000) < t_userData.getaward_push_time
	and t_userData.getaward_push_bid ~= nil
	and count_can_get_reward_task(t_userData.tasks) == 0 then
		t_userData.getaward_push_time = 0
		mis_bridge.modpush_cancel(t_params.uin, t_userData.getaward_push_bid, mis_config.s_mobpush_novice_task_mergePushId)
		mis_log.day("novice_task","modpush_cancel getaward_push|" .. t_params.uin .. '|' .. uu.to_str(t_userData.getaward_push_bid))
	end

	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 发奖
	if #t_award > 0 then
		n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_award, mis_config.t_workType.s_NOVICE_TASK, 'novice_task')
		if n_code ~= t_retCode.n_OK then
			mis_log.day("novice_task_error", "novice_task_getaward add_items error|" .. t_params.uin .. "|" .. n_subTaskId .. "|" .. uu.to_str(s_desc) .. "|" .. uu.to_str(s_items))
			return n_code, s_desc
		end
	end

	--埋点数据
	mis_log.remote_pure_day("novice_task_getaward", mis_common.table_to_json({
		key = "mission_system";
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = mis_data.get_server_time();
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		labelid = 9;
		taskid = n_subTaskId;
		bonusid = t_award;
		action = "finish";
	}))
	
	-- 客户端界面显示
	local t_tasks = {}
	for k, v in pairs(t_userData.tasks) do
		t_tasks[k] = {}
		for k2, v2 in pairs(v) do
			t_tasks[k][k2] = { progress = v2.progress, status = v2.status }
		end
	end
	
	t_resp = {
		tasks = t_tasks[1],
		awards = t_award
	}
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务全部领取
-- 返回：n					状态码
--		ts 					描述
this.novice_task_getaward_total = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_nowtime 		= mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData
	local t_resp, t_tasks, t_award, t_awardClassify, s_items

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_task data error'
	end

	-- 刷新任务，并领取全部奖励
	n_code, t_tasks, t_award, t_awardClassify = novice_task_status_core(t_userData, t_conf.t_taskList, mis_config.t_missionGetAward.ALL)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 判断是否取消推送领奖提示（已注册且未推送，没有已完成未领奖任务）
	-- getaward_push_time == 0 表示还未推送就被取销了，也算未曾推送过
	-- getaward_push_time 不是nil也不是0，表示已经推送过或者已经注册推送
	if t_userData.getaward_push_time ~= nil
	and (n_nowtime * 1000) < t_userData.getaward_push_time
	and t_userData.getaward_push_bid ~= nil
	and count_can_get_reward_task(t_userData.tasks) == 0 then
		t_userData.getaward_push_time = 0
		mis_bridge.modpush_cancel(t_params.uin, t_userData.getaward_push_bid, mis_config.s_mobpush_novice_task_mergePushId)
		mis_log.day("novice_task","modpush_cancel getaward_push 2|" .. t_params.uin .. '|' .. uu.to_str(t_userData.getaward_push_bid))
	end
	
	n_code, s_desc   = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	if mis_uu.tableNotEmpty(t_award) then
		n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_award, mis_config.t_workType.s_NOVICE_TASK, 'novice_task')
		if n_code ~= t_retCode.n_OK then
			mis_log.day("novice_task_error", "novice_task_getaward_total add_items error|" .. t_params.uin .. "|" .. n_code .. "|" .. uu.to_str(s_desc) .. "|" .. uu.to_str(s_items))
			return n_code, s_desc
		end
	end

	-- 异步埋点
	mis_timer:new():ngx_timer_at(0, function()
		for n_subTaskId, t_subAward in pairs(t_awardClassify) do
			mis_log.remote_pure_day("novice_task_getaward", mis_common.table_to_json({
				key = "mission_system";
				ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
				uin = t_params.uin;
				time = ngx.time();
				country = t_params.country or 'nil';
				apiid = t_params.apiid or 'nil';
				ver = t_params.ver or 'nil';
				lang = t_params.lang or 'nil';
				labelid = 9;
				taskid = n_subTaskId;
				bonusid = t_subAward;
				action = "finish";
			}))
		end
	end)

	t_resp = {
		tasks = t_tasks[1],
		awards = t_award
	}
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务过期奖励领取
-- 返回：n					状态码
--		ts 					描述
this.novice_task_getaward_expire = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local n_event			= t_params.event
	local s_workType		= mis_config.t_workType.s_NOVICE_TASK
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_nowtime 		= mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData
	local t_resp, s_items

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user daily_sign data error'
	end

	if n_nowtime > t_userData.notice_end_time then
		return t_retCode.n_OPER_ERR, "expire"
	end

	if mis_uu.tableNotEmpty(t_userData.expire_award) then
		n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_userData.expire_award, mis_config.t_workType.s_NOVICE_TASK, 'novice_task')
		if n_code ~= t_retCode.n_OK then
			mis_log.day("novice_task_error", "novice_task_getaward_expire add_items error|" .. t_params.uin .. "|" .. n_code .. "|" .. uu.to_str(s_desc) .. "|" .. uu.to_str(s_items))
			return n_code, s_desc
		end
		t_userData.expire_award = {}
	end
	
	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	t_resp = {
		awards = t_userData.expire_award or {}
	}
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新手任务大奖领取
-- 返回：n					状态码
--		ts 					描述
this.novice_task_getaward_final = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local n_select			= t_params.award_select
	local s_workType		= mis_config.t_workType.s_NOVICE_TASK
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_nowtime 		= mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData
	local t_resp, t_award, t_awardAdd, s_items

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user daily_sign data error'
	end

	if t_userData.final_award_status ~= 1 then
		mis_log.day("novice_task_error", "novice_task_getaward_final status error|" .. '|' .. n_uin .. '|' .. uu.to_str(t_userData))
		return t_retCode.n_OPER_ERR, "status error"
	end

	t_award = t_conf.t_finalSuitAward[n_select]
	if not mis_uu.tableNotEmpty(t_award) then
		mis_log.day("novice_task_error", "novice_task_getaward_final select error|" .. '|' .. n_uin .. '|' .. uu.to_str(n_select))
		return t_retCode.n_OPER_ERR, "select error"
	end

	t_awardAdd = {}
	for i = 1, #t_award do
		table_insert(t_awardAdd, {id = t_award[i].itemId, num = t_award[i].num})
	end

	-- 设置为已领取状态
	t_userData.final_award_status = 2
	t_userData.final_award_select = n_select

	n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_awardAdd, s_workType, 'novice_task_final')
	if n_code ~= t_retCode.n_OK then
		mis_log.day("novice_task_error", "novice_task_getaward_expire add_items error|" .. t_params.uin .. "|" .. n_code .. "|" .. uu.to_str(s_desc) .. "|" .. uu.to_str(s_items))
		return n_code, s_desc
	end
	
	-- 判断是否取消推送接新手任务提示
	-- final_award_push_time == 0 表示还未推送就被取销了，也算未曾推送过
	-- final_award_push_time 不是nil也不是0，表示已经推送过或者已经注册推送
	if t_userData.final_award_push_time ~= nil
	and (n_nowtime * 1000) < t_userData.final_award_push_time
	and t_userData.final_award_push_bid ~= nil then
		t_userData.final_award_push_time = 0
		mis_bridge.modpush_cancel(t_params.uin, t_userData.final_award_push_bid, mis_config.s_mobpush_novice_task_mergePushId)
		mis_log.day("novice_task","modpush_cancel final_award_push|" .. t_params.uin .. '|' .. uu.to_str(t_userData.final_award_push_bid))
	end

	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	
	--埋点数据
	mis_log.remote_pure_day("novice_task_getaward", mis_common.table_to_json({
		key = "mission_system";
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = mis_data.get_server_time();
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		labelid = 9;
		taskid = 99;
		bonusid = t_awardAdd;
		action = "finish";
	}))

	t_resp = {
		awards = t_awardAdd
	}
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：新用户进入商城领取福利(迷你豆)
-- 返回：n					状态码
--		ts 					描述
this.novice_newuser_status = function()
	local n_code, s_desc, t_user, t_userData, t_resp, t_newUserAward

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_newuser data error'
	end

	t_userData.new_user_award 	= t_userData.new_user_award or {}
	t_newUserAward           	= t_userData.new_user_award
	t_newUserAward.state  		= t_newUserAward.state or 0

	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	t_resp = {
		new_user_award = t_userData.new_user_award
	}

	return t_retCode.n_OK, t_resp
end
--------------------------------------------------------------
-- 说明：新用户进入商城领取福利(迷你豆)
-- 返回：n					状态码
--		ts 					描述
this.novice_newuser_event = function()
	local t_conf 			= mis_data.t_novice_task.t_conf
	local n_code, s_desc, t_user, t_userData, t_resp, t_newUserAward

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_novice_task_data()
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user novice_newuser data error'
	end

	t_userData.new_user_award 	= t_userData.new_user_award or {}
	t_newUserAward           	= t_userData.new_user_award
	if t_newUserAward.state and t_newUserAward.state == 1 then
		return t_retCode.n_REWARD_HAS_RECEIVED
	end

	n_code, s_desc = novice_newuser_getaward(t_newUserAward, t_conf)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	n_code, s_desc = t_user:set_novice_task_data(t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	t_resp = {
		new_user_award = t_userData.new_user_award
	}

	return t_retCode.n_OK, t_resp
end
--------------------------------------------------------------
-- 说明：任务业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_share_mission = function()
	local t_params  		= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local n_nowtime 		= mis_data.get_server_time()

	if t_taskConf.n_status ~= mis_config.t_workStatus.n_ENABLE then
		mis_log.day("share_mission_error","pre_share_mission status disable|" .. t_params.uin .. '|' .. s_type)
		return t_retCode.n_OPER_ERR, 'share_mission disable'
	end

	-- 活动有效期间
	if n_nowtime < t_taskConf.t_conf.n_startTime or n_nowtime > t_taskConf.t_conf.n_endTime then
		mis_log.day("share_mission_error","pre_share_mission out of time|" .. t_params.uin .. '|' .. s_type .. '|' .. t_params.act)
		return t_retCode.n_OPER_ERR, 'Activity is out of validity!'
	end

	-- 渠道控制
	if mis_uu.tableNotEmpty(t_taskConf.t_conf.t_apiids) then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)

		for _, v in pairs(t_taskConf.t_conf.t_apiids) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if not b_valid_apiid then
			mis_log.day("share_mission_error","pre_share_mission apiid is invalid|" .. t_params.uin .. '|' .. s_type .. "|" .. n_apiid)
			return t_retCode.n_OPER_ERR, 'apiid is invalid'
		end
	end

	if mis_uu.tableNotEmpty(t_taskConf.t_conf.t_noapiids) then
		local b_valid_apiid  = false
		local n_apiid  =  tonumber(t_params.apiid or 0)

		for _, v in pairs(t_taskConf.t_conf.t_apiids) do
			if v and tonumber(v) == n_apiid then
				b_valid_apiid = true
				break
			end
		end
		if b_valid_apiid then
			mis_log.day("share_mission_error","pre_share_mission noapiid is invalid|" .. t_params.uin .. '|' .. s_type .. "|" .. n_apiid)
			return t_retCode.n_OPER_ERR, 'apiid is invalid - ' .. n_apiid
		end
	end

	-- 版本号控制
	local n_l = mis_common.version_to_number(t_params.ver or 0)
	local n_r = t_taskConf.t_conf.n_version_min
	if n_l < n_r then
		mis_log.day("share_mission_error","pre_share_mission version too low|" .. t_params.uin .. '|' .. s_type .. "|" .. n_l)
		return t_retCode.n_OPER_ERR, 'version too low'
	end

	-- 业务逻辑延申处理
	if mis_extend.missionPre[s_type] then
		local n_code, s_desc = mis_extend.missionPre[s_type]()
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：任务状态核心逻辑
-- 		b_addItem			是否发放道具奖励
-- 返回：n					状态码
--		ts 					描述
local share_mission_status_core = function(t_user, t_userData, s_type, t_resp, b_addItem)
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local n_nowtime 		= mis_data.get_server_time()
	local n_code, s_desc, t_autoAward

	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_mission) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end
	
	t_userData.tasks		 = t_userData.tasks or {}
	t_userData.tasks[s_type] = t_userData.tasks[s_type] or {}

	t_autoAward = {share = {}, items = {}}
	-- 通过配置表刷新玩家任务
	t_taskConf = t_taskConf.t_conf
	for k, v in pairs(t_taskConf.t_mission) do

		for k2, v2 in pairs(v) do
			local n_subTaskId	= v2.n_subTaskId
			local t_task 		= t_userData.tasks[s_type][n_subTaskId]
			local b_update  	= false
			local n_status		= 0
			local n_refreshTime = 0
			local n_progress	= 0
			local n_total		= nil

			if t_task then
				-- 自动领取奖励
				if t_taskConf.b_auto and t_task.status == 1 and v2.t_bonus and mis_uu.tableNotEmpty(v2.t_bonus) 
				and	mis_common.is_another_day(t_task.refreshTime, n_nowtime) then
					if mis_extend.missionAwardCore[s_type] then
						-- 业务自定义处理
						mis_extend.missionAwardCore[s_type](t_userData, s_type, n_subTaskId, 1, v2, t_autoAward)
					else
						mis_extend.share_mission_getaward_core(t_userData, s_type, n_subTaskId, 1, v2, t_autoAward)
					end
					t_task = t_userData.tasks[s_type][n_subTaskId]
				end
				-- 刷新任务
				if v2.b_daily and mis_common.is_another_day(t_task.refreshTime, n_nowtime) then
					b_update = true
				end
				if v2.b_weekly and mis_common.is_another_week(t_task.refreshTime, n_nowtime) then
					b_update = true
				end
				-- 任务累计数量
				if b_update and t_task.total then
					n_total = t_task.total
				end
			end

			-- 更新任务
			if not t_task or b_update == true then
				t_task = { progress = n_progress, status = n_status, event = k, refreshTime = n_refreshTime, rewardTime = 0, mode = 0, total = n_total }
			end
			t_userData.tasks[s_type][n_subTaskId] =  t_task
		end
	end

	-- 触发登录任务
	n_code, s_desc = mis_extend.share_mission_event_core(t_userData, s_type, 18, 1)
	if n_code ~= t_retCode.n_OK and n_code ~= t_retCode.n_NO_EVENT_TYPE then
		mis_log.day("share_mission_error","share_mission_event login error|" .. t_user.n_uin .. '|' .. uu.to_str(n_code) .. '|' .. s_type .. '|' .. s_desc)
	end

	-- 客户端界面显示
	t_resp = t_resp or { tasks = {} }

	-- 业务逻辑延申处理
	if mis_extend.missionStatus[s_type] then
		local n_code, s_desc = mis_extend.missionStatus[s_type](t_user, t_userData, t_autoAward, t_resp, t_taskConf.n_exchange_type)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	if t_resp.tasks then
		for k, v in pairs(t_userData.tasks[s_type]) do
			t_resp.tasks[k] = { progress = v.progress, status = v.status, event = v.event, total = v.total }
		end
	end
	
	-- 发放普通道具（注意：为防刷道具，发放逻辑必须放在全部处理成功后）
	if b_addItem then
		if #t_autoAward.items > 0 then
			n_code, s_desc = mis_data.add_items(t_user.n_uin, t_autoAward.items, s_type, 'auto_award')
			if n_code ~= t_retCode.n_OK then
				mis_log.day("share_mission_error","share_mission_status add_items error|" .. t_user.n_uin .. '|' .. s_type .. '|' .. uu.to_str(n_code) .. '|' .. uu.to_str(s_desc) .. '|' .. uu.to_str(t_autoAward))
				return n_code, s_desc
			end
		end
	end
	
	return t_retCode.n_OK, t_resp, t_autoAward
end

--------------------------------------------------------------
-- 说明：任务状态
-- 返回：n					状态码
--		ts 					描述
this.share_mission_status = function()
	local t_params 			= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local n_nowtime 		= mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData, t_autoAward, t_resp

	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_mission) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end
	
	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	n_code, t_resp = share_mission_status_core(t_user, t_userData, s_type, nil, true)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_resp
	end

	n_code, s_desc   = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	
	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：触发任务
-- 参数：event				任务
--		value				增量
--      mission_type		活动类型
-- 返回：n					状态码
--		ts 					描述
this.share_mission_event = function()
	local t_params  		= ngx.ctx.t_params
	local n_event			= t_params.event
	local n_value			= t_params.value
	local s_type			= t_params.mission_type
	local n_code, s_desc, t_user, t_userData

	t_user = mis_data.get_user()
	n_code, t_userData 	= t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("share_mission_error","share_mission_event get user data error|" .. t_params.uin .. '|' .. s_type)
		return n_code, t_userData
	end

	t_userData.tasks		 = t_userData.tasks or {}
	t_userData.tasks[s_type] = t_userData.tasks[s_type] or {}

	-- 事件触发核心逻辑
	if mis_extend.missionEventCore[s_type] then
		-- 业务自定义处理
		n_code, s_desc = mis_extend.missionEventCore[s_type](t_userData, s_type, n_event, n_value)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	else
		-- 更新任务进度
		n_code, s_desc = mis_extend.share_mission_event_core(t_userData, s_type, n_event, n_value)
		if n_code ~= t_retCode.n_OK then
			mis_log.day("share_mission_error","share_mission_event core error|" .. t_params.uin .. '|' .. uu.to_str(n_code) .. '|' .. s_type .. '|' .. n_event  .. '|' .. s_desc)
			return n_code, 'share mission event core error'
		end
	end

	-- 客户端界面显示
	local t_resp = { tasks = {} }
	if t_userData.tasks and t_userData.tasks[s_type] then
		for k, v in pairs(t_userData.tasks[s_type]) do
			t_resp.tasks[k] = { progress = v.progress, status = v.status, event = v.event, total = v.total }
		end
	end

	-- 业务逻辑延申处理
	if mis_extend.missionEvent[s_type] then
		local n_code, s_desc = mis_extend.missionEvent[s_type](t_user, t_userData, t_resp)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("share_mission_error","share_mission_event save error|" .. t_params.uin .. '|' .. uu.to_str(n_code) .. '|' .. s_type)
		return n_code, s_desc
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：任务领奖
-- 返回：n					状态码
--		ts 					描述
this.share_mission_getaward = function()
	local t_params 			= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local t_taskConf 		= uu.table_value_copy(mis_data.t_share_mission[s_type])
	local n_subTaskId		= t_params.taskId
	local t_mission, t_task, t_award, t_temp	= {}, {}, {}, {}
	local n_code, s_desc, t_user, t_userData

	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_mission) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end

	-- 获取子任务配置
	t_temp = t_taskConf.t_conf
	for k, v in pairs(t_temp.t_mission) do
		for k2, v2 in pairs(v) do
			if v2.n_subTaskId and n_subTaskId == v2.n_subTaskId then
				t_mission = v2
				break
			end
		end
	end

	if not (t_mission and mis_uu.tableNotEmpty(t_mission)) then
		mis_log.day("share_mission_error", "share_mission_getaward mission not exist|" .. t_params.uin .. '|' .. s_type .. "|" .. uu.to_str(n_subTaskId))
		return t_retCode.n_PARAM_ERR, "mission not exist"
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error|' .. s_type
	end

	t_award = {share = {}, items = {}}
	if mis_extend.missionAwardCore[s_type] then
		-- 业务自定义处理
		local n_code, s_desc = mis_extend.missionAwardCore[s_type](t_userData, s_type, n_subTaskId, 0, t_mission, t_award)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	else
		n_code, s_desc = mis_extend.share_mission_getaward_core(t_userData, s_type, n_subTaskId, 0, t_mission, t_award)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end

	end

	local reason_flag = 'share_mission_getaward'
	--大数据需要统计
	if mis_config.reason_flag[s_type] then
		reason_flag = reason_flag .. '_' .. s_type
	end


	-- 发放普通道具
	if #t_award.items > 0 then
		n_code, s_desc = mis_data.add_items(t_params.uin, t_award.items, s_type, reason_flag)
		if n_code ~= t_retCode.n_OK then
			mis_log.day("share_mission_error","share_mission_getaward add_items error|" .. t_params.uin .. '|' .. s_type .. '|' .. uu.to_str(n_code) .. '|' .. uu.to_str(s_desc) .. '|' .. uu.to_str(t_award))
			return n_code, s_desc
		end
	end

	-- 客户端界面显示
	local t_resp = { tasks = {}, bonus = t_award }
	if t_userData.tasks and t_userData.tasks[s_type] then
		for k, v in pairs(t_userData.tasks[s_type]) do
			t_resp.tasks[k] = { progress = v.progress, status = v.status, event = v.event }
		end
	end
	
	
	-- 业务逻辑延申处理
	if mis_extend.missionAward[s_type] then
		local n_code, s_desc = mis_extend.missionAward[s_type](t_user, t_userData, t_award, t_resp, t_temp.n_exchange_type)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end
	
	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：道具兑换
-- 返回：n					状态码
--		ts 					描述
this.share_mission_exchange = function()
	local t_params 			= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local t_taskConf 		= uu.table_value_copy(mis_data.t_share_mission[s_type])
	local n_itemId 			= t_params.itemId
	local n_itemNum 		= t_params.itemNum
	local s_logType			= s_type .. '_exchange'
	local n_remainNum, n_price, n_total = 0, 0, 0

	local n_code, s_desc, s_items, ts_desc, t_user, t_userData
	local t_store, t_goods = {}, {}
	local n_nowTime			= mis_data.get_server_time()

	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_store) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end

	t_store = t_taskConf.t_conf.t_store
	if n_nowTime < t_store.n_startTime or n_nowTime > t_store.n_endTime then
		mis_log.day("share_mission_error", "invalid time|" .. t_params.uin .. '|' .. t_store.n_startTime .. '|' .. t_store.n_endTime)
		return t_retCode.n_OPER_ERR, 'invalid time'
	end
	if n_itemId <= 0 and n_itemNum <= 0 then
		mis_log.day("share_mission_error", "param error|" .. t_params.uin .. '|' .. n_itemId .. '|' .. n_itemNum .. '|' .. s_type)
		return t_retCode.n_PARAM_ERR, 'param error'
	end
	if not (t_store.t_goods and t_store.t_goods[n_itemId] and t_store.t_goods[n_itemId].price and
			t_store.t_goods[n_itemId].t_items and mis_uu.tableNotEmpty(t_store.t_goods[n_itemId].t_items)) then
		return t_retCode.n_PARAM_ERR, 'goods is not exist'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	t_goods   	= uu.table_value_copy(t_store.t_goods[n_itemId])
	n_price   	= t_goods.price
	n_total   	= n_itemNum * n_price
	n_remainNum = tonumber(t_userData.exchange_num or 0)

	if n_total > n_remainNum or n_total <= 0 then
		mis_log.day("share_mission_error", "num not enough|" .. t_params.uin .. '|' .. n_total .. '|' .. n_remainNum .. '|' .. s_type)
		return t_retCode.n_PARAM_ERR, 'exchange num is not enough'
	end

	for k, v in pairs(t_goods.t_items) do
		if v.id and v.num then
			t_goods.t_items[k].num= v.num * n_itemNum
		end
	end
	t_userData.record 			= t_userData.record or {}
	t_userData.record[n_itemId] = t_userData.record[n_itemId] or 0
	t_userData.record[n_itemId] = t_userData.record[n_itemId] + n_itemNum

	-- 兑换次数限制
	if t_goods.limit and t_goods.limit > 0 and t_userData.record[n_itemId] > t_goods.limit then
		mis_log.day("share_mission_error", "exceed the limit|" .. t_params.uin .. '|' .. n_itemId .. '|' .. t_goods.limit .. '|' .. s_type)
		return t_retCode.n_PARAM_ERR, 'exceed the limit'
	end

	-- 已拥有不予兑换，帐号服校验
	if t_goods.unique and t_goods.unique == 1 then
		local t_contentId = {}
		local b_exist 	  = false
		for k, v in pairs(t_goods.t_items) do
			if v.id then table.insert(t_contentId, v.id) end
		end
		n_code, ts_desc = mis_bridge.check_item_exist(t_params.uin, mis_common.table_to_json(t_contentId))
		if n_code ~= t_retCode.n_OK then
			mis_log.day("share_mission_error", "check_item_exist|" .. t_params.uin .. '|' .. mis_common.table_to_json(t_contentId))
			return n_code, ts_desc
		end
		for _, t_ in pairs(ts_desc) do
			if t_.canget == false then
				b_exist = true
				break
			end
		end
		if b_exist then
			mis_log.day("share_mission_error", "already owned|" .. t_params.uin .. '|' .. mis_common.table_to_json(t_contentId))
			return t_retCode.n_OPER_ERR, 'already owned'
		end
	end

	-- 发放道具
	n_code, s_desc, s_items = mis_data.add_items(t_params.uin, t_goods.t_items, s_type, s_logType)
	if n_code ~= t_retCode.n_OK then
		mis_log.day('share_mission_error', 'exchange goods|' .. t_params.uin .. '|' .. s_items .. '|' .. s_type)
		return n_code, s_desc
	end

	-- 扣除兑奖券
	t_userData.exchange_num = n_remainNum - n_total

	local t_resp =  { num = n_remainNum - n_total, t_goods = t_goods.t_items }
	
	-- 业务逻辑延申处理
	if mis_extend.missionExchange[s_type] then
		local n_code, s_desc = mis_extend.missionExchange[s_type](t_user, t_userData, t_resp)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	--埋点数据
	mis_log.remote_pure_day(s_logType, mis_common.table_to_json({
		key = 'store_exchange';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = n_nowTime;
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		bonus = t_goods.t_items or 'nil';
	}))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：奖励活动代币
-- 返回：n					状态码
--		ts 					描述
this.share_mission_add_currency = function()
	local t_params 			= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local n_uin 			= t_params.uin
	local n_value 			= t_params.value
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local s_logType			= s_type .. '_add_currency'
	local s_clientIP 		= ngx.ctx.xff
	local n_code, s_desc, t_user, t_userData, n_addTotal

	-- ip白名单校验
	n_code, s_desc = mis_allowIp.ip_allow("share_mission_currency", s_clientIP)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("share_mission_add_currency_error", "ip not allow|" .. t_params.uin .. '|' .. uu.to_str(s_clientIP) .. "|" .. s_desc .. "|" .. s_type .. "|" .. n_value)
		return t_retCode.n_OPER_ERR, 'ip not allow'
	end

	-- 是否允许赠送
	if t_taskConf.t_conf.t_currency.n_allowAdd ~= 1 then
		mis_log.day("share_mission_add_currency_error", "not allow add|" .. t_params.uin .. '|' .. s_clientIP)
		return t_retCode.n_OPER_ERR, 'not allow add'
	end

	-- 只增不减
	if n_value <= 0 then
		mis_log.day("share_mission_add_currency_error", "value invalid|" .. t_params.uin .. '|' .. n_value)
		return t_retCode.n_OPER_ERR, 'value invalid'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("share_mission_add_currency_error", "get user data error|" .. t_params.uin .. '|' .. n_value)
		return n_code, 'get user data error'
	end

	-- 单次奖励数量限制
	if t_taskConf.t_conf.t_currency.n_addCurrencyUpperValue
	and n_value > t_taskConf.t_conf.t_currency.n_addCurrencyUpperValue then
		mis_log.day("share_mission_add_currency_error", "value invalid|" .. t_params.uin .. '|' .. n_value)
		return t_retCode.n_OPER_ERR, 'value invalid'
	end

	-- 总奖励次数限制
	if t_taskConf.t_conf.t_currency.n_addCurrencyUpperCount
	and (t_userData.add_currency_count or 0) > t_taskConf.t_conf.t_currency.n_addCurrencyUpperCount then
		mis_log.day("share_mission_add_currency_error", "add count overflow|" .. t_params.uin .. '|' .. t_userData.add_currency_count)
		return t_retCode.n_OPER_ERR, 'add count overflow'
	end

	n_addTotal = t_userData.add_currency_total or 0

	-- 总奖励数量限制
	if t_taskConf.t_conf.t_currency.n_addCurrencyTotalValue then
		if n_addTotal >= t_taskConf.t_conf.t_currency.n_addCurrencyTotalValue then
			mis_log.day("share_mission_add_currency_error", "add value overflow|" .. t_params.uin .. '|' .. t_userData.add_currency_total)
			return t_retCode.n_OPER_ERR, 'add value overflow'
		end
		
		if n_addTotal + n_value > t_taskConf.t_conf.t_currency.n_addCurrencyTotalValue then
			mis_log.day("share_mission_add_currency", "add value overflow partially|" 
				.. t_params.uin .. '|' .. n_addTotal .. "|" .. n_value .. "|" 
				.. t_taskConf.t_conf.t_currency.n_addCurrencyTotalValue)
			n_value = t_taskConf.t_conf.t_currency.n_addCurrencyTotalValue - n_addTotal
		end
	end

	t_userData.add_currency_count = (t_userData.add_currency_count or 0) + 1
	t_userData.add_currency_total = (t_userData.add_currency_total or 0) + n_value

	local t_resp = {}

	if mis_extend.missionAddCurrency[s_type] then
		-- 业务自定义处理
		local n_code, s_desc = mis_extend.missionAddCurrency[s_type](t_user, t_userData, t_resp, n_value)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	else
		if t_taskConf.t_conf.t_currency.n_exchange_type == 1 then
			t_userData.award_num = t_userData.award_num or {}
			t_userData.award_num[s_type] = (t_userData.award_num[s_type] or 0) + n_value
			t_resp.award_num = t_userData.award_num[s_type]
		else
			t_userData.exchange_num = (t_userData.exchange_num or 0) + n_value
			t_resp.exchange_num = t_userData.exchange_num
		end
	end
	
	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end
	
	--埋点数据
	mis_log.remote_pure_day(s_logType, mis_common.table_to_json({
		key = 'add_currency';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = mis_data.get_server_time();
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		type = s_type;
		value = n_value;
	}))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：道具兑换状态
-- 返回：n					状态码
--		ts 					描述
this.share_exchange_status = function()
	local t_params 			= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]

	local n_code, s_desc, t_user, t_userData
	local t_remain, t_record = {}

	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_store) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type, true)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	t_record = t_userData.record or {}

	-- 剩余可兑换次数
	for k, v in pairs(t_taskConf.t_conf.t_store.t_goods) do
		if v.limit and v.limit > 0 then
			table_insert(t_remain, {id = k, num = math_max(v.limit - (t_record[k] or 0), 0)})
		end
	end

	local t_resp =  { exchange_num = t_userData.exchange_num, t_remain = t_remain }
	
	-- 业务逻辑延申处理
	if mis_extend.missionExchangeStatus[s_type] then
		local n_code, s_desc = mis_extend.missionExchangeStatus[s_type](t_user, t_userData, t_resp)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：请求分享码
-- 返回：n					状态码
--		ts 					描述
this.share_request_code = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local t_sysUser 		= mis_data.get_user(0)
	local n_now				= mis_data.offset_now_v2(t_taskConf)
	local t_shareCode		= t_taskConf.t_conf.t_shareCode or {}
	local b_ok, n_code, s_desc, s_code, t_codeData
	local t_user, t_userData

	-- 加个锁，防止刷票
	b_ok, s_desc = t_cache:add(s_type .. "share_request_code" .. n_uin, 1, 0.2)
	if not b_ok then
		log.day_list("share_code_error" ,"share_request_code", "request frequently", s_type, n_uin, uu.to_str(s_desc))
		return t_retCode.n_OPER_ERR, 'request frequently'
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error" ,"share_request_code", "get user data error", s_type, n_uin, n_code, uu.to_str(t_userData))
		return n_code, 'get user data error'
	end

	t_userData.share_code = t_userData.share_code or {}

	-- 一天只能申请一个码
	if t_userData.share_code[s_type]
	and os_date("%Y%m%d", t_userData.share_code[s_type].ctime) == os_date("%Y%m%d", n_now) then
		return t_retCode.n_OK, { code = t_userData.share_code[s_type].code }
	end

	s_code, s_desc = mis_calcu.new_share_code(s_type, t_shareCode.t_prefix, t_shareCode.n_init, t_shareCode.n_max)
	if s_code == nil then
		log.day_list("share_code_error","share_request_code","new_share_code error", s_type, n_uin, uu.to_str(s_desc))
		return t_retCode.n_SYS_ERR, "new share code error"
	end

	log.day_list("share_code" ,"share_request_code", "new code", s_type, n_uin, uu.to_str(s_code))

	-- 虚拟加读锁，防止报错
	t_sysUser:add_share_code_read_lock(s_type, s_code)

	t_codeData = {ctime = n_now, uin = n_uin, exchange = 0, exchange_users = {}}
	n_code, s_desc = t_sysUser:set_share_code_data(s_type, s_code, t_codeData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_request_code", "save sys code error", n_uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end
	
	t_userData.share_code[s_type] = {ctime = n_now, code = s_code}
	
	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_request_code", "save user code error", n_uin, uu.to_str(n_code), uu.to_str(s_desc), uu.to_str(t_userData.share_code))
		return n_code, s_desc
	end

	return t_retCode.n_OK, { code = s_code }
end

--------------------------------------------------------------
-- 说明：分享密码兑换
-- 返回：n					状态码
--		ts 					描述
this.share_code_exchange = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local s_code 			= t_params.code
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local t_shareCode		= t_taskConf.t_conf.t_shareCode or {}
	local n_maxLength       = t_shareCode.n_maxLength or 20
	local s_codePattern     = t_shareCode.s_pattern or "^%W+%d[0-9a-zA-Z]+$"
	local n_maxExchange     = t_shareCode.n_maxExchange or 2
	local n_codeExpireType  = t_shareCode.n_expireType or 1
	local n_codeExpire      = t_shareCode.n_expire
	local n_now				= mis_data.offset_now_v2(t_taskConf)
	local t_sysUser 		= mis_data.get_user(0)
	local n_code, s_desc, t_user, t_userData
	local t_codeData, t_codeUser, t_codeUserData

	-- 判断参数是否有效
	if not s_code or #s_code > n_maxLength or string_match(s_code, s_codePattern) == nil then
		log.day_list("share_code_error", "share_code_exchange", "s_code invalid", s_type, n_uin, uu.to_str(s_code))
		return t_retCode.n_PARAM_ERR, 'code invalid'
	end

	n_code, t_codeData = t_sysUser:get_share_code_data(s_type, s_code)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_code_exchange", "get_share_code_data error", s_type, n_uin, uu.to_str(n_code), uu.to_str(t_codeData))
		return n_code, t_codeData
	end

	-- 密码不存在
	if t_codeData.uin == nil then
		log.day_list("share_code_error", "share_code_exchange", "code not exists", s_type, n_uin, uu.to_str(t_codeData), uu.to_str(s_code))
		return t_retCode.n_SHARE_CODE_INVALID, "code not exists"
	end

	if t_codeData.uin == n_uin then
		log.day_list("share_code_error", "share_code_exchange", "can't exchange self", s_type, n_uin, uu.to_str(t_codeData))
		return t_retCode.n_SHARE_CODE_SELF_LIMIT, "can't exchange self"
	end

	-- 最大兑换次数限制
	if t_codeData.exchange >= n_maxExchange then
		log.day_list("share_code_error", "share_code_exchange", "exchange excess", s_type, n_uin, uu.to_str(t_codeData), n_maxExchange)
		return t_retCode.n_SHARE_CODE_EXCESS, "exchange excess"
	end
	
	-- 一个用户同一个码只能兑换一次
	if t_codeData.exchange_users and t_codeData.exchange_users[n_uin] then
		log.day_list("share_code_error", "share_code_exchange", "exchange repeated", s_type, n_uin, uu.to_str(t_codeData))
		return t_retCode.n_SHARE_CODE_REPEATED, "exchange repeated"
	end

	-- 过期判断
	if not n_codeExpireType or n_codeExpireType == 1 then
		if os_date("%Y%m%d", t_codeData.ctime) ~= os_date("%Y%m%d") then
			log.day_list("share_code_error", "share_code_exchange", "code expire 1", s_type, n_uin, uu.to_str(n_code), uu.to_str(t_codeData))
			return t_retCode.n_SHARE_CODE_EXPIRE, "code expire"
		end
	elseif n_codeExpireType == 2 then
		if n_codeExpire and (n_now - t_codeData.ctime) > n_codeExpire then
			log.day_list("share_code_error", "share_code_exchange", "code expire 2", s_type, n_uin, uu.to_str(n_code), uu.to_str(t_codeData))
			return t_retCode.n_SHARE_CODE_EXPIRE, "code expire"
		end
	end

	t_codeData.exchange = t_codeData.exchange + 1
	t_codeData.exchange_users = t_codeData.exchange_users or {}
	t_codeData.exchange_users[n_uin] = 1

	n_code, s_desc = t_sysUser:set_share_code_data(s_type, s_code, t_codeData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_code_exchange", "save error", s_type, n_uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	-- 发奖励
	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_code_exchange", "get_share_mission_data error", s_type, n_uin, uu.to_str(n_code), uu.to_str(t_userData))
		return n_code, t_userData
	end

	-- 更新任务
	n_code, s_desc = mis_extend.share_mission_event_core(t_userData, s_type, 28, 1)
	if n_code ~= t_retCode.n_OK and n_code ~= t_retCode.n_NO_EVENT_TYPE then
		log.day_list("share_code_error", "share_code_exchange", "update mission fail", s_type, n_uin, uu.to_str(n_code), uu.to_str(s_desc))
	end

	-- 业务扩展处理，目前仅处理活动无关业务
	local t_rsp = {}
	local t_callbackData = { items = {}}
	if mis_extend.missiopCode[s_type] then
		mis_extend.missiopCode[s_type](t_user, t_userData, t_codeData, t_callbackData, t_rsp)
	end

	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_code_exchange", "set_share_mission_data fail", s_type, n_uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	if uu.tableNotEmpty(t_callbackData.items) then
		n_code, s_desc = mis_data.add_items(t_params.uin, t_callbackData.items, s_type, 'share_code_exchange')
		if n_code ~= t_retCode.n_OK then
			log.day_list("share_code_error","share_code_exchange","add_items error",t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(t_callbackData.items))
		end
	end

	-- 分享者发奖励
	t_codeUser = mis_data.get_user(t_codeData.uin)
	n_code, t_codeUserData = t_codeUser:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_code_exchange", "get_share_mission_data error", s_type, t_codeData.uin, uu.to_str(n_code), uu.to_str(t_codeUserData))
		return n_code, t_codeUserData
	end

	-- 更新任务
	n_code, s_desc = mis_extend.share_mission_event_core(t_codeUserData, s_type, 29, 1)
	if n_code ~= t_retCode.n_OK and n_code ~= t_retCode.n_NO_EVENT_TYPE then
		log.day_list("share_code_error", "share_code_exchange", "update mission fail", s_type, t_codeData.uin, uu.to_str(n_code), uu.to_str(s_desc))
	end

	n_code, s_desc = t_codeUser:set_share_mission_data(s_type, t_codeUserData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_code_error", "share_code_exchange", "set_share_mission_data fail", s_type, t_codeData.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	log.day_list("share_code", "share_code_exchange", "ok", n_uin, uu.to_str(t_codeData), t_codeData.uin, uu.to_str(t_codeUserData))

	return t_retCode.n_OK, t_rsp
end

--------------------------------------------------------------
-- 说明：抽奖状态
-- 返回：n					状态码
--		ts 					描述
this.share_roll_status = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local n_apiid			= tonumber(t_params.apiid)
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local n_now				= mis_data.offset_now_v2(t_taskConf)
	local n_code, s_desc, t_user, t_userData
	local t_rollConf, n_freeRemain, n_videoRemain

	if not (t_taskConf.t_conf and t_taskConf.t_conf.t_shareRoll) then
		log.day_list("share_roll_error" ,"share_roll_status", "no roll config", s_type, n_uin, n_code, uu.to_str(t_userData))
		return t_retCode.n_WORK_ERR, 'no roll config'
	end

	t_rollConf = t_taskConf.t_conf.t_shareRoll

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_roll_error" ,"share_roll_status", "get user data error", s_type, n_uin, n_code, uu.to_str(t_userData))
		return n_code, 'get user data error'
	end

	t_userData.share_roll = t_userData.share_roll or {}

	-- 每日刷新
	if not t_userData.share_roll.roll_refresh_time 
	or (t_rollConf.n_daily == 1 
		and os_date("%Y%m%d", t_userData.share_roll.roll_refresh_time ) ~= os_date("%Y%m%d", n_now))
	then
		t_userData.share_roll.free_roll_count = 0
		t_userData.share_roll.video_roll_count = 0
		t_userData.share_roll.roll_refresh_time = n_now
	end

	n_freeRemain = math_max(((t_rollConf.n_freeCount or 0) - (t_userData.share_roll.free_roll_count or 0)), 0)
	if n_apiid and t_rollConf.t_videoApiidAllow[n_apiid] then
		n_videoRemain = math_max(((t_rollConf.n_videoCount or 0) - (t_userData.share_roll.video_roll_count or 0)), 0)
	else
		n_videoRemain = 0
	end

	local t_resp =  { 
		free_roll_count = n_freeRemain, 
		video_roll_count = n_videoRemain 
	}
	
	-- 业务逻辑延申处理
	if mis_extend.shareRollStatus[s_type] then
		local n_code, s_desc = mis_extend.shareRollStatus[s_type](t_user, t_userData, t_resp)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end
	
	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_roll_error" ,"share_roll_status", "set_share_mission_data error", s_type, n_uin, n_code, uu.to_str(s_desc), uu.to_str(t_userData))
		return n_code, s_desc
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：抽奖
-- 返回：n					状态码
--		ts 					描述
this.share_roll = function()
	local t_params 			= ngx.ctx.t_params
	local n_uin 			= t_params.uin
	local n_apiid			= tonumber(t_params.apiid)
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local n_now				= mis_data.offset_now_v2(t_taskConf)
	local n_code, s_desc, t_user, t_userData
	local t_rollConf, n_freeRemain, n_videoRemain
	
	if not (t_taskConf.t_conf and t_taskConf.t_conf.t_shareRoll) then
		log.day_list("share_roll_error" ,"share_roll", "no roll config", s_type, n_uin, n_code, uu.to_str(t_userData))
		return t_retCode.n_WORK_ERR, 'no roll config'
	end

	t_rollConf = t_taskConf.t_conf.t_shareRoll

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_roll_error" ,"share_roll", "get user data error", s_type, n_uin, n_code, uu.to_str(t_userData))
		return n_code, 'get user data error'
	end

	t_userData.share_roll = t_userData.share_roll or {}
	
	n_freeRemain = (t_rollConf.n_freeCount or 0) - (t_userData.share_roll.free_roll_count or 0)
	if n_apiid and t_rollConf.t_videoApiidAllow[n_apiid] then
		n_videoRemain = (t_rollConf.n_videoCount or 0) - (t_userData.share_roll.video_roll_count or 0)
	else
		n_videoRemain = 0
	end

	-- 免费次数已用完
	if (t_rollConf.n_freeCount or 0) > 0 and n_freeRemain <= 0 then
		-- 判断视频次数
		if (t_rollConf.n_videoCount or 0) > 0 and n_videoRemain <= 0 then
			log.day_list("share_roll_error" ,"share_roll", "no roll count", s_type, n_uin, n_code, uu.to_str(t_userData))
			return t_retCode.n_SHARE_NO_ROLL_COUNT, 'no roll count'
		end

		-- 判断视频间隔
		if n_now < (t_userData.share_roll.video_refresh_time or 0) then
			log.day_list("share_roll_error" ,"share_roll", "counting down", s_type, n_uin, n_code, uu.to_str(t_userData))
			return t_retCode.n_OPER_ERR, 'counting down'
		else
			t_userData.share_roll.video_refresh_time = n_now + (t_rollConf.n_minVideoInterval or 2)
			t_userData.share_roll.video_roll_count = t_userData.share_roll.video_roll_count + 1
		end
	else
		t_userData.share_roll.free_roll_count = t_userData.share_roll.free_roll_count + 1
	end
	
	n_freeRemain = math_max(((t_rollConf.n_freeCount or 0) - (t_userData.share_roll.free_roll_count or 0)), 0)
	if n_apiid and t_rollConf.t_videoApiidAllow[n_apiid] then
		n_videoRemain = math_max(((t_rollConf.n_videoCount or 0) - (t_userData.share_roll.video_roll_count or 0)), 0)
	else
		n_videoRemain = 0
	end

	local t_resp =  { free_roll_count = n_freeRemain, video_roll_count = n_videoRemain }

	-- 业务逻辑延申处理
	if mis_extend.shareRoll[s_type] then
		local n_code, s_desc = mis_extend.shareRoll[s_type](t_user, t_userData, t_resp)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end
	
	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("share_roll_error" ,"share_roll", "set_share_mission_data error", s_type, n_uin, n_code, uu.to_str(s_desc), uu.to_str(t_userData))
		return n_code, s_desc
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：年度投票前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_annual_contest = function()
	return this.pre_share_mission()
end

--------------------------------------------------------------
-- 说明：年度投票状态
-- 返回：n					状态码
--		ts 					描述
this.annual_contest_status = function()
	local t_params 			= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local n_nowtime 		= mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData, t_awardNum
	local t_vote, t_candidates, t_attention, t_attentionList

	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_mission) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end
	
	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	n_code, t_vote = mis_annualVote.get_vote_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, t_vote
	end

	-- 查询关注状态
	if not t_userData.attention_refresh_time
	or (n_nowtime - t_userData.attention_refresh_time) > 10 then
		t_attention = {}
		n_code, t_attentionList = mis_bridge.query_attention_list(t_params.uin)
		if n_code ~= t_retCode.n_OK then
			mis_log.day('annual_contest_error', 'query_attention_list error|' .. t_params.uin .. '|' .. uu.to_str(n_code) .. '|' .. uu.to_str(t_attention))
		elseif #t_attentionList > 0 then
			for i = 1, #t_attentionList do
				t_attention[t_attentionList[i]] = 1
			end
		end
		t_userData.attention = t_attention
		t_userData.attention_refresh_time = n_nowtime
	else
		t_attention = t_userData.attention
	end

	t_candidates = {}
	for k, v in pairs(t_taskConf.t_conf.t_candidate) do
		table_insert(t_candidates, {uin = k, vote = t_vote[k] or v, attention = t_attention[k] or 0})
	end

	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	t_awardNum = t_userData.award_num or {}

	-- 客户端界面显示
	local t_resp = {
		award_num = t_awardNum[s_type] or 0,
		exchange_num = t_userData.exchange_num or 0,
		candidates = t_candidates
	}

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：年度投票投票
-- 返回：n					状态码
--		ts 					描述
this.annual_contest_vote = function()
	local t_params 			= ngx.ctx.t_params
	local s_type			= t_params.mission_type
	local n_targetUin		= t_params.target_uin
	local t_taskConf 		= mis_data.t_share_mission[s_type]
	local n_nowTime 		= mis_data.get_server_time()
	local n_code, s_desc, t_user, t_userData, t_awardNum
	local n_vote, t_candidates, t_attention

	--if t_params.uin ~= 1000042652 and n_targetUin == 1000042652 then
	--	return t_retCode.n_OPER_ERR, "此账号投票测试中，请投给其他账号"
	--end
	
	-- 加个锁，防止刷票
	local b_ok, e_err, b_f = t_cache:add("annual_contest_vote" .. t_params.uin, 1, 0.2)
	if not b_ok then
		return t_retCode.n_OPER_ERR, 'vote frequently'
	end

	if not(t_taskConf and t_taskConf.t_conf and t_taskConf.t_conf.t_mission) then
		return t_retCode.n_WORK_ERR, 'The mission is not exist!'
	end

	-- 不是有效候选人
	if t_taskConf.t_conf.t_candidate[n_targetUin] == nil then
		return t_retCode.n_OPER_ERR, 'target invalid'
	end

	-- 投票已结束
	if n_nowTime > t_taskConf.t_conf.n_startEndTime then
		return t_retCode.n_OPER_ERR, 'vote is over'
	end
	
	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	-- 检查投票卷
	if not t_userData.award_num or not t_userData.award_num[s_type] or 
	t_userData.award_num[s_type] < 1 then
		return t_retCode.n_OPER_ERR, 'vote ticket empty'
	end

	-- 消耗投票卷，获得兑换卷
	t_userData.award_num[s_type] = t_userData.award_num[s_type] - 1
	t_userData.exchange_num = (t_userData.exchange_num or 0) + 1

	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 投票
	n_code, s_desc = mis_annualVote.vote(s_type, n_targetUin, 1)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 投票结果查询
	n_code, n_vote = mis_annualVote.get_vote_data(s_type, n_targetUin)
	if n_code ~= t_retCode.n_OK then
		return n_code, n_vote
	end
	
	t_attention = t_userData.attention or {}

	t_candidates = {{uin = n_targetUin, vote = n_vote, attention = t_attention[n_targetUin] or 0}}
	
	t_awardNum = t_userData.award_num or {}

	-- 客户端界面显示
	local t_resp = {
		award_num = t_awardNum[s_type] or 0,
		exchange_num = t_userData.exchange_num or 0,
		candidates = t_candidates
	}

	--埋点数据
	mis_log.remote_pure_day("annual_contest_vote", mis_common.table_to_json({
		key = 'annualselection_vote';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = n_nowTime;
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		type = s_type;
		candidateid = n_targetUin;
	}))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：迷你派对制作蛋糕
-- 返回：n					状态码
--		ts 					描述
this.make_mini_cake = function()
	local t_params 			= ngx.ctx.t_params
	local n_value			= t_params.value
	local s_type			= t_params.mission_type
	local t_conf			= mis_data.t_share_mission[s_type].t_conf
	local t_cakeConf		= t_conf.t_cake
	local t_bonus			= t_conf.t_bonus
	local s_logType			= s_type .. '_getaward'
	local n_nowTime 		= mis_data.get_server_time()

	local n_code, n_deduct
	local s_txt, s_desc
	local t_user, t_userData, t_task, t_tasks

	if not (t_cakeConf and t_bonus and t_bonus.itemId and t_bonus.num ) then
		return t_retCode.n_SYS_ERR
	end

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error|' .. s_type
	end

	-- 扣除原材料
	t_tasks = t_userData.tasks[s_type]

	for k, v in pairs(t_cakeConf) do
		t_task 		= t_tasks[k]
		n_deduct 	=  v.num * n_value

		if t_task.total and t_task.total >= n_deduct then
			t_task.total = t_task.total - n_deduct
		else
			s_txt = "ingredient not enough |" .. t_params.uin .. '|' .. (v.id or 0) .. '|' .. (t_task.total or 0) .. '|' .. n_value
			mis_log.day("share_mission_error", s_txt)
			return t_retCode.n_WORK_ERR, s_txt
		end
	end

	-- 制作蛋糕奖励
	t_userData.tasks[s_type] 	= t_tasks

	-- 客户端界面显示
	local t_resp = { tasks = {} }
	if t_userData.tasks and t_userData.tasks[s_type] then
		for k, v in pairs(t_userData.tasks[s_type]) do
			t_resp.tasks[k] = { progress = v.progress, status = v.status, event = v.event, total = v.total }
		end
	end

	-- 业务逻辑延申处理
	local t_award = {share = {[1]={ id=t_bonus.itemId, num=t_bonus.num * n_value }}, items = {}}
	if mis_extend.missionAward[s_type] then
		local n_code, s_desc = mis_extend.missionAward[s_type](t_user, t_userData, t_award, t_resp, t_conf.n_exchange_type)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	n_code, s_desc = t_user:set_share_mission_data(s_type, t_userData)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("share_mission_error","make_mini_cake save error|" .. t_params.uin .. '|' .. uu.to_str(n_code) .. '|' .. s_type)
		return n_code, s_desc
	end

	--埋点数据
	mis_log.remote_pure_day(s_logType, mis_common.table_to_json({
		key = 'getaward';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = n_nowTime;
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		type = s_type;
		bonus = t_bonus.num * n_value;
	}))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：加入护卫队
-- 返回：n					状态码
--		ts 					描述
this.join_convoy = function()
	local t_params 			= ngx.ctx.t_params
	local n_inviteUin		= t_params.invite_uin
	local s_type			= t_params.mission_type
	local s_logType			= s_type .. '_getaward'
	local n_nowTime 		= mis_data.get_server_time()
	local t_taskConf		= mis_data.t_share_mission[s_type].t_conf

	local n_code, s_desc
	local t_user, t_userData
	local t_inviteUser, t_inviterData
	local t_captainUser, t_captainData
	local t_memberUser, t_memberData

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	-- 不能邀请自己
	if n_inviteUin == t_params.uin then
		mis_log.day("join_convoy_error","can't join self team|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. s_type)
		return t_retCode.n_OPER_ERR, "can't join self team"
	end

	-- 判断是否已经加入护卫队
	if t_userData.captain_uin ~= nil then
		mis_log.day("join_convoy_error","already join|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. t_userData.captain_uin .. '|' .. s_type)
		return t_retCode.n_CONVOY_ALREADY_JOIN, "already join convoy"
	end

	-- 找到队长
	t_inviteUser = mis_data.get_user(n_inviteUin)
	n_code, t_inviterData = t_inviteUser:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		mis_log.day("join_convoy_error","get inviter data error|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. s_type)
		return n_code, 'get inviter data error'
	end

	if t_inviterData.captain_uin == n_inviteUin then
		t_captainUser = t_inviteUser
		t_captainData = t_inviterData
	elseif t_inviterData.captain_uin ~= nil then
		t_captainUser = mis_data.get_user(t_inviterData.captain_uin)
		n_code, t_captainData = t_captainUser:get_share_mission_data(s_type)
		if n_code ~= t_retCode.n_OK then
			mis_log.day("join_convoy_error","get captain data error|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. s_type)
			return n_code, 'get captain data error'
		end
	else
		-- 新建护卫队
		t_inviterData.convoy = {}
		t_inviterData.captain_uin = n_inviteUin

		mis_log.day("join_convoy","new convoy|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. s_type)

		t_captainUser = t_inviteUser
		t_captainData = t_inviterData
	end

	if t_captainData.convoy == nil then
		mis_log.day("join_convoy_error","convoy not set up|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. t_captainUser.n_uin .. '|' .. s_type)
		return t_retCode.n_WORK_ERR, "convoy not set up"
	end

	-- 判断护卫队是否已满
	if #t_captainData.convoy >= t_taskConf.n_teamCapacity then
		mis_log.day("join_convoy_error","convoy is full|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. uu.to_str(t_captainData.captain_uin) .. '|' .. s_type .. '|' .. uu.to_str(t_captainData.convoy))
		return t_retCode.n_CONVOY_IS_FULL, "convoy is full"
	end

	-- 如果是新建的护卫队
	if #t_captainData.convoy == 0 then
		t_captainData.convoy[1] = t_captainUser.n_uin
		t_captainData.convoy[2] = t_params.uin
		t_userData.captain_uin = t_captainUser.n_uin
	else
		-- 加入已有护卫队
		t_captainData.convoy[#t_captainData.convoy + 1] = t_params.uin
		t_userData.captain_uin = t_captainUser.n_uin
	end

	-- 更新队员的任务进度
	for _, v in ipairs(t_captainData.convoy) do
		repeat
			if v == t_user.n_uin then
				t_memberUser = t_user
				t_memberData = t_userData
			elseif v == t_inviteUser.n_uin then
				t_memberUser = t_inviteUser
				t_memberData = t_inviterData
			elseif v == t_captainUser.n_uin then
				t_memberUser = t_captainUser
				t_memberData = t_captainData
			else
				t_memberUser = mis_data.get_user(v)
				n_code, t_memberData = t_memberUser:get_share_mission_data(s_type)
				if n_code ~= t_retCode.n_OK then
					mis_log.day("join_convoy_error","get member data error|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. s_type .. "|" .. t_memberUser.n_uin)
					break
				end
			end

			-- 确保任务数据初始化
			n_code, s_desc = share_mission_status_core(t_memberUser, t_memberData, s_type, nil, true)
			if n_code ~= t_retCode.n_OK then
				mis_log.day("join_convoy_error","get mission status error|" .. t_params.uin .. '|' .. n_inviteUin .. '|' .. s_type .. "|" .. t_memberUser.n_uin)
				break
			end
			
			-- 触发组队任务
			n_code, s_desc = mis_extend.share_mission_event_core(t_memberData, s_type, 33, #t_captainData.convoy)
			if n_code ~= t_retCode.n_OK and n_code ~= t_retCode.n_NO_EVENT_TYPE then
				mis_log.day("join_convoy_error","share_mission_event convoy error|" .. t_params.uin .. '|' .. uu.to_str(n_code) .. '|' .. s_type .. '|' .. s_desc .. "|" .. t_memberUser.n_uin .. "|" .. uu.to_str(t_memberData))
			end

			-- 保存用户数据
			n_code, s_desc = t_memberUser:set_share_mission_data(s_type, t_memberData)
			if n_code ~= t_retCode.n_OK then
				mis_log.day("join_convoy_error","join_convoy save error|" .. t_params.uin .. '|' .. uu.to_str(n_code) .. '|' .. s_type .. '|' .. s_desc .. "|" .. t_memberUser.n_uin)
				break
			end
		until true
	end

	-- 返回数据
	local t_resp = {members = {}}
	for k, v in ipairs(t_captainData.convoy) do
		table_insert(t_resp.members, v)
	end

	mis_log.day("join_convoy", "ok", uu.to_str(t_resp))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：周末好礼v2 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_weekend_gift_v2 = function()
	local t_params = ngx.ctx.t_params

	--现网屏蔽先
	-- if mis_config.n_debug ~= 1 then
	-- 	return t_retCode.n_OPER_ERR, 'weekend_gift disable2'
	-- end

	local t_conf = mis_data.t_weekend_gift_v2
	local n_now = mis_data.offset_now_v2(t_conf)
	if t_conf.n_status ~= mis_config.t_workStatus.n_ENABLE then
		return t_retCode.n_OPER_ERR, 'weekend_gift_v2 disable'
	end
	if t_conf.t_conf.n_startTime and n_now < t_conf.t_conf.n_startTime then
		return t_retCode.n_OPER_ERR, 'weekend_gift_v2 out of time'
	end
	if t_conf.t_conf.n_endTime and t_conf.t_conf.n_endTime < n_now then
		return t_retCode.n_OPER_ERR, 'weekend_gift_v2 out of time'
	end
	return t_retCode.n_OK
end

--------------------------------------------------------------
-- 说明：周末好礼v2 获取状态
-- 返回：n					状态码
--		ts 					描述
local get_weekend_gift_status_v2 = function(t_user, t_userData)
	-- 参与状态：0未开启，1已开启
	local t_conf = mis_data.t_weekend_gift_v2
	local n_now = mis_data.offset_now_v2(t_conf)
	local n_code, s_desc, t_userDataV1
	local n_giftLevel, n_rotateLevel

	local n_code, t_userDataV1 = t_user:get_weekend_gift_data(true)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","get_weekend_gift_status_v2","get user data v1 error",ngx.ctx.t_params.uin,uu.to_str(n_code),uu.to_str(t_userDataV1))
		return n_code, t_userDataV1
	end

	-- 判断是否已领v1奖励
	if t_userDataV1.subscribe_reward_time
	and os_date("%Y%W", n_now) == os_date("%Y%W", t_userDataV1.subscribe_reward_time) then
		n_rotateLevel = -1
	else	
		if t_userData.rotate_time == nil
		or os_date("%Y%W", n_now) ~= os_date("%Y%W", t_userData.rotate_time) then
			n_rotateLevel = 0
		else
			n_rotateLevel = t_userData.rotate_level
		end
	end
	
	-- 宝箱等级
	if t_userData.subscribe_push == 1 and t_userData.subscribe_calendar == 1 then
		n_giftLevel = 3
	elseif t_userData.subscribe_push == 1 or t_userData.subscribe_calendar == 1 then
		n_giftLevel = 2
	else
		n_giftLevel = 1
	end

	-- 回复数据
	local t_resp = {
		subscribe_push = t_userData.subscribe_push or 0,
		subscribe_calendar = t_userData.subscribe_calendar or 0,
		gift_level = n_giftLevel,
		rotate_level = n_rotateLevel,
	}

	log.day_list("weekend_gift_v2","get_weekend_gift_status_v2","ok",ngx.ctx.t_params.uin,uu.to_str(n_now),uu.to_str(t_userData),uu.to_str(t_resp))

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：周末好礼v2 状态
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_status_v2 = function()
	local t_params  		= ngx.ctx.t_params
	local s_type 			= mis_config.t_workType.s_WEEKEND_GIFT_V2
	local n_code, s_desc, t_user, t_userData, t_status

	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type, true)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_status_v2","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_userData))
		return n_code, t_userData
	end

	n_code, t_status = get_weekend_gift_status_v2(t_user, t_userData)

	return n_code, t_status
end

--------------------------------------------------------------
-- 说明：周末好礼v2 开关权限
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_subscribe_v2 = function()
	local t_params  		= ngx.ctx.t_params
	local s_type 			= mis_config.t_workType.s_WEEKEND_GIFT_V2
	local n_push			= t_params.push
	local n_calendar		= t_params.calendar
	local t_user 			= mis_data.get_user()
	local n_code, s_desc, t_userData, t_resp

	if n_push ~= 0 and n_push ~= 1 then
		log.day_list("weekend_gift_v2","weekend_gift_subscribe_v2","push error",t_params.uin)
		return t_retCode.n_OPER_ERR, 'push error'
	end
	
	if n_calendar ~= 0 and n_calendar ~= 1 then
		log.day_list("weekend_gift_v2","weekend_gift_subscribe_v2","calendar error",t_params.uin)
		return t_retCode.n_OPER_ERR, 'calendar error'
	end

	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_subscribe_v2","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_userData))
		return n_code, t_userData
	end

	t_userData.subscribe_push = n_push
	t_userData.subscribe_calendar = n_calendar

	n_code, s_desc = t_user:set_share_mission_data(s_type,t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_subscribe_v2","save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end
	
	if n_push == 1 then
		mis_bridge.modpush_register(t_user.n_uin, mis_config.s_mobpush_flag_weekend_gift_v2)
	else
		mis_bridge.modpush_unregister(t_user.n_uin, mis_config.s_mobpush_flag_weekend_gift_v2)
	end

	n_code, t_resp = get_weekend_gift_status_v2(t_user, t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_subscribe","get_weekend_gift_status_v2 error",t_params.uin,uu.to_str(n_code),uu.to_str(t_resp))
		return n_code, s_desc
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：周末好礼v2 订阅领奖
-- 返回：n					状态码
--		ts 					描述
this.weekend_gift_rotate_v2 = function()
	local t_params  		= ngx.ctx.t_params
	local s_type 			= mis_config.t_workType.s_WEEKEND_GIFT_V2

	local n_code, s_desc, t_userData, t_status
	local t_user = mis_data.get_user()
	local n_now = mis_data.offset_now_v2(mis_data.t_weekend_gift_v2)
	local n_weekday, n_week, n_hour, n_min
	local t_conf, t_bonus, t_award, t_awardPool
	local n_rand, n_sum

	-- 只能在周五、六、日抽奖
	n_weekday = tonumber(os_date("%w", n_now))
	if n_weekday ~= 5 and n_weekday ~= 6 and n_weekday ~= 0 then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","day error",t_params.uin, n_weekday)
		return t_retCode.n_OPER_ERR, "day error"
	end

	-- 配置
	t_conf 	= mis_data.t_weekend_gift_v2.t_conf

	-- 判断是否到达抽奖时间
	n_hour = tonumber(os_date("%H", n_now))
	n_min = tonumber(os_date("%M", n_now))
	if n_hour < t_conf.t_rotate_start.hour
	or n_hour > t_conf.t_rotate_end.hour
	or (n_hour == t_conf.t_rotate_start.hour and n_min < t_conf.t_rotate_start.min)
	or (n_hour == t_conf.t_rotate_end.hour and n_min > t_conf.t_rotate_end.min)
	then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","not reward time",t_params.uin,uu.to_str(n_hour),uu.to_str(n_min),uu.to_str(t_conf.t_rotate_start),uu.to_str(t_conf.t_rotate_end))
		return t_retCode.n_OPER_ERR, "not reward time"
	end

	n_code, t_userData = t_user:get_share_mission_data(s_type)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","get user data error",t_params.uin,uu.to_str(n_code),uu.to_str(t_userData))
		return n_code, t_userData
	end

	n_code, t_status = get_weekend_gift_status_v2(t_user, t_userData)
	if n_code ~= t_retCode.n_OK then
		return n_code, s_desc
	end

	-- 判断本周是否可领取订阅奖励
	if t_status.rotate_level ~= 0 then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","rotate_level error",t_params.uin,uu.to_str(t_userData))
		return t_retCode.n_OPER_ERR, "already got award"
	end

	t_userData.rotate_time = n_now
	t_userData.rotate_level = t_status.gift_level

	t_awardPool = t_conf.t_subscribe_award[t_status.gift_level]
	if t_awardPool == nil then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","subscribe_award conf miss",t_params.uin,uu.to_str(t_status))
		return t_retCode.n_WORK_ERR, "award config miss"
	end

    -- 加权随机选择奖励
    n_rand = math_random(1, t_awardPool.n_totalWeight)
    n_sum = 0
    for _, v in ipairs(t_awardPool.t_awards) do
		if (n_sum + 1) <= n_rand and n_rand <= n_sum + v.n_weight then
			t_bonus = v
			break
		end
		n_sum = n_sum + v.n_weight
    end

    if t_bonus == nil then
		log.day_list("weekend_gift_v2" ,"weekend_gift_rotate_v2", "roll config error", t_user.n_uin, n_rand, n_sum, uu.to_str(t_awardPool))
		return t_retCode.n_WORK_ERR, 'roll config error'
    end

	t_award = {{id = t_bonus.s_itemId, num = t_bonus.n_num}}
	t_userData.rotate_award = t_award

	n_code, s_desc = t_user:set_share_mission_data(s_type,t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","save error", t_params.uin, uu.to_str(n_code), uu.to_str(s_desc))
		return n_code, s_desc
	end

	n_code, s_desc = mis_data.add_items(t_params.uin, t_award, s_type, 'weekend_gift_rotate_v2')
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","add_items error",t_params.uin,uu.to_str(n_code),uu.to_str(s_desc),uu.to_str(t_award))
		return n_code, s_desc
	end

	--埋点数据
	mis_log.remote_pure_day("weekend_gift_rotate_v2", mis_common.table_to_json({
		key = 'getaward';
		ip = t_params.s_remoteAddr or ngx.ctx.xff or ngx.var.remote_addr or "nil";
		uin = t_params.uin;
		time = mis_data.get_server_time();
		country = t_params.country or 'nil';
		apiid = t_params.apiid or 'nil';
		ver = t_params.ver or 'nil';
		lang = t_params.lang or 'nil';
		gift_level = t_userData.rotate_level;
		bonus = t_award;
	}))

	n_code, t_status = get_weekend_gift_status_v2(t_user, t_userData)
	if n_code ~= t_retCode.n_OK then
		log.day_list("weekend_gift_v2","weekend_gift_rotate_v2","get_weekend_gift_status_v2 error",t_params.uin,uu.to_str(n_code),uu.to_str(t_status))
		return n_code, s_desc
	end

	local t_resp = {
		award = t_award,
		status = t_status
	}

	return t_retCode.n_OK, t_resp
end


this.bind_phone_rewards = function()
	local s_type = ngx.ctx.t_params.mission_type
	local t_resp = {}
	local n_code, t_user, t_userData, t_award

	if not s_type then
		return t_retCode.n_PARAM_ERR, 's_type error'
	end
	local t_Config = mis_data.t_share_mission[s_type] or {}
	local t_conf = t_Config.t_conf
	if not (t_conf and t_conf.t_bind_phone ) then
		return t_retCode.n_PARAM_ERR, 'config error'
	end
	t_user = mis_data.get_user()
	n_code, t_userData = t_user:get_share_mission_data(s_type)

	if n_code ~= t_retCode.n_OK then
		return n_code, 'get user data error'
	end

	if mis_extend.bind_phone_deal[s_type] then
		local n_code, s_desc = mis_extend.bind_phone_deal[s_type](t_user, t_userData, t_conf.t_bind_phone, t_resp)
		if n_code ~= t_retCode.n_OK then
			return n_code, s_desc
		end
	end

	return t_retCode.n_OK, t_resp
end

--------------------------------------------------------------
-- 说明：三丽鸥 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_sanrio = function()
	return mis_sanrio.sanrio_check_limit()
end


--------------------------------------------------------------
-- 说明：moon 业务前置检测
-- 返回：n					状态码
--		ts 					描述
this.pre_moon = function()
	return mis_moon.pre_moon()
end

return this
